株式会社グローバルゲート公式ブログ

Blog

2020-12-02

コールバック関数を使ってslickをカスタマイズしてみよう

こんにちは。グローバルゲート制作部のモーリーです。
気がつけば12月に入り、2020年もラストスパートという季節になってしまいました。恐ろしいことです…。

2020年を振り返ると残念ながら悪いニュースが多く、あまりよい年ではありませんでした。少し気が早いですが、2021年は私自身も当社も皆様のお力になれるように尽力できればと思います。


さて、本日の記事ではスライドショーの定番プラグインであるslickのコールバック関数を使いこなし、個性的なスライドショーを実装してみたいと思います。

画像が左右に流れたりフェードイン・フェードアウトしたりするスライドショーはよく見かけると思います。
それで十分なケースも多々ありますが、もうちょっと個性的に…ということで、画像を分割してその1単位ごとにアニメーションをつけることで面白い効果をつくってみました。



DEMO
ソースコード全文(Github)

チェック模様は最近の流行ですね。ムーっ!



slickとは


slickはjQueryプラグインとして動作するスライドショーです。シンプルなHTMLと簡単なJavascriptだけでスライドショーを設置することができ、カスタマイズ性にも優れています。

the last carousel you’ll ever need」だそうです。自分で言いますか


コールバック関数とは

プログラミングにおいて、他のコードの引数として渡されるサブルーチンである。これにより、低レベルの抽象化層が高レベルの層で定義されたサブルーチン(または関数)を呼び出せるようになる。
Wikipedia


…とのことですが、意味がよく分かりません…。
乱暴に言ってしまうと「指定したタイミングで実行される関数」のことです。Javascriptに限らずどの言語でも「処理が行われる前や後に実行する」というかたちで実装されることが多いです。

slickに限ったことではありませんが、スライドショーやモーダルなどのアニメーションが関係するプラグインはコールバック関数を理解するとカスタマイズの幅が大きく広がります。表現力を広げるためにもぜひ覚えたい概念です。


slickでのコールバック関数

slickは以下のようなコールバック関数をオプションで指定することができます。

afterChange
スライドが切り替わった直後に実行されます。

beforeChange
スライドが切り替わる直前に実行されます。

breakpoint
ブレークポイントが設定されている場合、ウインドウサイズがそのブレークポイントを超えた直後に実行されます。

destroy
slickを破棄するタイミングで実行されます。

edge
スライドショーが無限にループする設定でないとき、最後か最後のスライドに到着したタイミングで実行されます。

init
slickが読み込まれ、初期化されたタイミングで実行されます。

reInit
slickが2度目以降に初期化されたタイミングで実行されます。

setPosition
位置やサイズが変更されたタイミングで実行されます。

swipe
スワイプによるスクロールが行われた直後に実行されます。

lazyLoaded
画像の遅延読み込みが行われ、完了したタイミングで実行されます。

lazyLoadError
画像の遅延読み込みが失敗したときに実行されます。


この中で今回は「init」「setPosition」「beforeChange」「afterChange」を使ったカスタマイズをご紹介したいと思います。
実際にコードを書いていきましょう。

HTML

slickは非常にシンプルなHTMLで実装することができます。
最小構成は以下のようになります。
	<div class="your-class">
	  <div>your content</div>
	  <div>your content</div>
	  <div>your content</div>
	</div>

今回は画像を扱い、そしてカスタマイズしやすいようにいくつかクラスを追加したHTMLを使用します。

   <div class="slick animation1">
       <div><img src="img/img1.jpg" class="slick-image" alt=""></div>
       <div><img src="img/img2.jpg" class="slick-image" alt="">
       </div>
       <div><img src="img/img3.jpg" class="slick-image" alt=""></div>
   </div>

slick用のcssとjsファイルの読み込みも忘れないように行います。

   <link rel="stylesheet" type="text/css" href="slick.css" />
   <link rel="stylesheet" type="text/css" href="slick-theme.css" />

   <!-- ~中略~ -->

   <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
   <script type="text/javascript" src="https://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
   <script type="text/javascript" src="slick.min.js"></script>

Javascript

initへのコールバック
画像をタイル状に分割するために複数のdivを並べ、そのdivの背景にスライドショー用の画像を指定します。
ジグソーパズルをイメージすると分かりやすいかもしれません。

       //分割数。奇数にするとバランスがよい。
       var x = 7;
       var y = 5;
       var $slick = $('.slick');

       var initSlick = function (slick, x, y) {
           $(slick.$slider).find('.slick-slide').each(function (key, value) {
               $(value).append('<div class="slick-boxWrapper" />');
               var img = $(value).find('.slick-image').attr('src');

               var slickBox = '';
               for (let i = 0; i < x * y; i++) {
                   slickBox += '<div class="slick-box" style="background-image: url(' + img +
                       '); width: ' + 100 / x + '%; height: ' + 100 /
                       y + '%" />';
               }
               $(value).find('.slick-boxWrapper').append(slickBox);
           })
       }

initとsetPositionへのコールバック
initへのコールバックでdivを並べることとができましたが、backgroundのsizeとpositionを調整して1枚の画像に見えるようにします。
この関数はinitだけでなくスライドショー自体のサイズが変わったときにも実行しないとズレてしまいますので、setPositionでも使用します。

       var setBg = function (slick) {
           $(slick.target).find('.slick-slide').each(function (key, value) {
               var w = $(value).width();
               var h = $(value).height();
               var imgW = $(value).find('.slick-image').get(0).naturalWidth;
               var imgH = $(value).find('.slick-image').get(0).naturalHeight;

               var setW, setH, fixW, fixH;

               if (imgW > imgH) {
                   //横長の画像のとき
                   setH = h;
                   setW = imgW * (h / imgH)
               } else {
                   //縦長の画像のとき
                   setW = w;
                   setH = imgH * (w / imgW);
               }
               //ずらす
               fixW = (setW - w) / 2;
               fixH = (setH - h) / 2;

               $(value).find('.slick-box').css({
                   backgroundSize: setW + 'px ' + setH + 'px'
               }).each(function (key2, value2) {
                   var positionX = key2 % x / x;
                   var positionY = Math.floor(key2 / x) / y;
                   $(value2).css({
                       backgroundPosition: ((-1 * positionX * w) - fixW) + 'px ' + ((-1 *
                           positionY * h) - fixH) + 'px'
                   });
               });
           })
       }

beforeChangeへのコールバック
あとは分割されたdivに対してアニメーションを実行するだけで完成です。
アニメーションはクラスを付加し、CSSで行います。

beforeChangeでslick-animateというクラスを付加します。

       var startAnimation = function (slick, currentSlide) {
           $(currentSlide.$slider[0]).find('.slick-active').addClass('slick-animate');
       }

そしてそのslick-animateというクラスに対してtransitionを設定します。

       .animation1.slick-initialized .slick-box {
           transform: scale(1, 0);
           transform-origin: center top;
           transition: 0.8s transform cubic-bezier(0.25, 1, 0.5, 1);
       }

       .animation1.slick-initialized .slick-box:nth-child(even) {
           transform-origin: center bottom;
       }

       .animation1.slick-initialized .slick-box:nth-child(3n) {
           transform: scale(0, 1);
           transform-origin: left center;
       }

       .animation1.slick-initialized .slick-box:nth-child(4n) {
           transform: scale(0, 1);
           transform-origin: right center;
       }

       .animation1.slick-initialized .slick-animate .slick-box {
           transform: scale(1, 1);
       }

DEMOではバリエーションとしてその他4種類のアニメーションを作成してみました。アニメーション部分はCSSのみで簡単なのでソースコードをご参照ください。

afterChangeへのコールバック
このままでは1周目はslick-animateクラスが付加されたタイミングでアニメーションが実行されるものの、2周目はそのクラスが残っているのでアニメーションになりません。そこでafterChangeでslick-animateクラスを外します。

       $slick.on('afterChange', function (slick, currentSlide) {
           startAnimation(slick, currentSlide);
       });

実行
ここまで定義した関数をコールバックとして指定し、slickを実行します。

       //初期化時に実行される
       $slick.on('init', function (event, slick, direction) {
           initSlick(slick, x, y);
           setBg(slick);
           setTimeout(function () {
               startAnimation(slick, slick);
           }, 500)
       });

       //初期化時とウインドウリサイズ時に実行される
       $slick.on('setPosition', function (slick) {
           setBg(slick);
       });

       //アニメーション開始前に実行される
       $slick.on('beforeChange', function (slick, currentSlide, nextSlide) {
           endAnimation(slick, currentSlide);
       });

       //アニメーション完了後に実行される
       $slick.on('afterChange', function (slick, currentSlide) {
           startAnimation(slick, currentSlide);
       });

       //Slick.js本体の実行
       $slick.slick({
           fade: true,
           speed: 0,
           autoplay: true,
           pauseOnFocus: false,
           pauseOnHover: false
       });

まとめ

コールバック関数は一見すると難しそうに見えますが、「どのタイミングでどんな処理を実行したいか」を意識すると理解もしやすいと思います。slick以外のスライドショーを使用するときもぜひ挑戦してみてください。

自分でつくるのは難しい、単なるスライドショーでは物足りないというお客様はぜひグローバルゲートにWebサイト制作をご用命ください。

ご相談・お問い合わせ

当社サービスについてのお問い合わせは下記までご連絡下さい。

お電話でのお問い合わせ

06-6121-7581 / 03-6415-8161