【Vue.js】SlickでreInit()が効かない?v-forで動的生成後に対応する方法

 前回、vue.js版のSlickに関して基本的な使い方を簡単に紹介(下記記事参照)させていただきましたが、axiosで非同期通信をしたり画像をプリロードしてからv-for文等で動的にコンテンツを生成した場合に、Slickを適用しようとすると正常に動作してくれない問題に直面にしたので、今回はその解決方法を備忘録も兼ねて紹介したいと思います。

環境

 まず、今回の環境ですが前回同様下記の環境を前提に進めていきたいと思います。

今回の環境

  • Webpack環境(v4.29.6)
  • vue v2.9.6
  • Node.js v10.12.0

 Webpackのインストール、構築方法は下記記事で紹介しています。

画像をプリロードしてv-for文で動的生成する

 では、まず下記のようなサンプルファイルを作成してみたいと思います。

 このファイルの内容と流れは下記のようになっています。

サンプルファイルの概要

  • photos配列に画像ファイル名が格納されている
  • photos配列をforeachで回してそれぞれの画像をプリロード
  • 画像のプリロードが完了したらloadedPhotosに画像パスを格納
  • loadedPhotosをv-for文で回して動的にコンテンツを生成

 基本的な概要は上記の通りとなっており、imgタグを囲っているdivには「photo」というクラス名を付与してデフォルトでは透明度を0にして、全ての画像のプリロードが完了した段階で見えるようにしています。

Slickを適用してみる

 では、このサンプルファイルにSlickを適用してみたいと思いますが、まず公式に記載されている方法から推測して下記のように記述してみたいと思います。ちなみに、この記述では正常に動作しません。

正常に動作しない例

 こんな感じでv-for文でループさせた対象コンテンツをslickタグで囲んで、動画のプリロードが完了した段階で、公式のGithubに記載されているreInit()関数を実行するようにしました。

 reInit()関数に「Helpful if you have to deal with v-for to update dynamic lists」とコメントアウトで記載があるように、動的生成したリストを再定義する関数のように思いますが、これだと正常に表示してくれないんですね。生成されたソースコードを見てみると、v-for文で生成したリストがごっそりなくなって何も表示されない状態になってしまいます。

 これがバグなのか説明不足で何か他の処理が必要なのかはわかりませんが、公式だけ見ただけだとこのように記述する人も多いかと思います。

解決した方法

 では、どうすればいいのかということで、個人的に試行錯誤してたどり着いた方法が下記になります。

 この方法を簡単にまとめると下記のようになります。

解決方法のポイント

  • watchでloadedPhotosを監視する
  • loadedPhotosがアップデートされたらreInit()を実行
  • reSlick()関数は使わずslick.destroy()で初期化
  • slick.create()関数で再描画
  • slick.goTo()で最初のスライドに戻す

 こういった流れになります。一応これで解決というか求めていたような結果になりました。ポイントはv-forでループさせたい配列データをWatchで監視することと、reSlick()ではなくslick.create()関数を使うことですね。

まとめ

 ということで、今回はVue.js版のSlickのバグかどうかはわかりませんが、非同期通信や画像のプリロード後にslickを適用する場合に起こる不具合の解決方法を紹介させていただきました。

 この方法が正しい方法かどうか分かりませんし、もっとスマートな方法もありそうな気もするので、もっと良い方法がある場合は是非教えてください〜。

 てことで、今回はここまで!また!

お仕事のご相談・ご依頼
お気軽にお問い合わせください!

お仕事の依頼はこちら

著者プロフィール

Takanori Hashi

東京、奄美大島、宮崎の拠点にサーフィンとスノーボードが好きなフリーランスのWebクリエイターです。普段はプログラム書いたりデザインしたり映像作ったりしています。いろいろな人の話しを聞くのが好きなので、このブログを通して多くの人と繋がりが出来たら嬉しいです。noteとInstagramもやっているのでフォローしてくれたらありがたいです!

人気記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です