slick.js というカルーセルを提供する jQuery プラグインを使ったときのメモ

slick.js という、カルーセル (スライドショー) を提供する jQuery プラグインを使って、少々本来の意図とは異なる使い方をしてちょっとつまづいたのでメモしておく。

slick.js の基本的な使い方は解説しないので、公式や以下のまとめを参照のこと。

バージョンによって API が大きく変わっていたり、破壊的な変更も多いプラグインなので、巷の StackOverflow なんかに書かれたコードがそのまま動かない場合もあったりして厄介だった。

今回やろうとしていたこと

今回 slick.js を使ってやろうとしていたのは、ユーザ操作によってカルーセル内に要素を自由に追加・削除できるような機能だった。

カルーセルの要素数が動的に変化し、それに合わせてカルーセル全体の表示幅も変更したり、といったことをしていた。

カルーセルの先頭に要素を追加するとき

カルーセルの先頭に要素を追加したいとき、カルーセルの要素数が 0 個のときは Insert Before を true にするとバグるので、要素数をみて slickAdd の呼び方を切り替える必要がある。

// (追加したい要素を抱えた DOM 要素と思ってください)
var newItem;

// 要素追加前のカルーセル内の要素の数を数えておく
// ここでいう .item クラスは、カルーセル内の各要素に振っている自前のクラス名なので、.slick-slide と同意。
var beforeItemLength = $('.item').length;
// 要素追加後のカルーセルの要素数
var afterItemLength = beforeSlickItemLength + 1;

// カルーセルの要素数に応じてカルーセル全体の幅を変更していたので、その処理…
$('#itemsWrapper').css('width', (afterItemLength * 100) + 'px');
// 表示する要素数の変更は slick() を叩く
$('#itemsWrapper').slick('slickSetOption', 'slidesToShow', afterItemLength);
// この辺を自前でやらないといけなかったのが面倒な案件でした。w

// 肝心の要素追加部分。現在の要素数に応じて処理を振り分ける
if(beforeItemLength === 0) {
  // 現在の要素数が 0 個の場合はオプション指定なしで追加する
  $('#itemsWrapper').slick('slickAdd', newItem);
}
else {
  // 現在の要素が1つ以上ある場合は Insert Before オプションを指定して先頭 (左端) に追加する
  $('#itemsWrapper').slick('slickAdd', newItem, 0, true);
}

カルーセルの要素を削除するとき

カルーセルから要素を削除する時は slickRemove という API を使うのだが、この API、slickAdd のときと違って要素の添字を更新してくれない (slickAdd した場合は自動的に data-slick-index 属性値を書き換えてくれる)。

そこで、slickRemove で要素を削除した際は、以下のようにして自前で添字を修正してやる必要がある。

// 削除したい要素の添字を取得する
// ここでは変数「removeId」の値に合致する id 属性値を持つ要素が削除対象とする。
// その要素から data-slick-index 属性の値を取得しておく。
var removeIndex = $('.item').filter(function() {
  return ($(this).attr('id') == removeId);
}).attr('data-slick-index');

// 要素数を変更した際の幅変更や表示要素数の変更処理は別途やっておく

// 添字を指定して要素を削除する
$('itemsWrapper').slick('slickRemove', removeIndex);

// ココで要素の添字を再修正する
// カルーセルの各要素には .slick-slide というクラスが振られているので、これらを扱う
var i = 0;
$('#itemsWrapper .slick-slide').each(function() {
  $(this).attr('data-sliick-index', i);
  i++;
});

画面内のダイアログとの組み合わせで表示がバグる

jQueryUI Dialog や、Bootstrap なんかで導入できる画面内に Lightbox 風に浮かび上がるダイアログ。

こうしたダイアログを、カルーセルの要素内に置いたボタンから開けるようにしていたのだが、ダイアログを閉じたときに動作がおかしくなることがあった。

どうやらダイアログを閉じた時に、直前に選択したカルーセル要素にフォーカスが当たることが問題を起こしているようだったので、カルーセルからダイアログを開く時に、カルーセル以外の別の要素にフォーカスを当てることで回避した。

「カルーセル内の要素をクリックするとその要素を削除する」といった動作をさせるときも、このフォーカスが問題になっていたので、カルーセルの操作前にはフォーカスを逃がすようにしていた。

// カルーセル内にある「開く」ボタンを押すとダイアログが開く作り。
$('.item .btn-open').on('click', function() {
  // カルーセル外にある別の要素にフォーカスを逃しておく
  $('#btn-confirm').focus();
  
  // jQueryUI のダイアログを開くなど処理…
  $('#dialog').dialog( /* 省略 */ );
});

slick.js 標準の矢印記号のスタイリング

.slick-prev.slick-next という要素が、矢印記号の表示領域を作っている。そしてそれぞれの :before 擬似要素に content プロパティで文字が設定されている。

IE で見た時に、この矢印記号のアイコンが少し欠けて見えていたので、表示位置や色とともに調整した。

.slick-prev,
.slick-next {
  height:30px;  /* 少し表示領域を広げた */
  top:30%;  /* カルーセル内の要素に合わせて表示位置をズラしたり */
}

.slick-prev:before,
.slick-next:before {
  color:#08f;  /* 矢印記号の色を変えたり */
}

以上。こういうプラグインの類って、それぞれのプラグインの学習コストが高くて、かつ応用が効かない知識ばかりになるのでつらい。