この記事でわかること
背景
気持ちとしてはこういうことをしたかった。
vue
のシンタックスハイライトが効かなかったので別々で……
<template> <div class='cards is-slick'> <div class='card' v-for="element in elements"> <element></element> </div> </div> </template>
export default Vue.extend({ data() { return { elements: [] } }, methods: { async getElements(){ HTTP.get('/api/elements').map(x => Element.new(x)) } }, // mounted か created かはともかく async created() { this.elements = await getElements() } })
雰囲気はわかってくれると思う。雰囲気はね。
で、問題は <div class='cards is-slick'>
を slick でカルーセルにしたい。
なので、とりあえずこうやって見る
// ... mounted() { $('.is-slick').slick() }
これは動かない。何故かと言うと、 slick はそのイベントが発火した時点のdivしか補足できず、新たに読み込まれた div はカルーセルの対象外になってしまうためだ。 つまり
<div class='cards is-slick'> <div class='card' v-for="element in elements"> </div> </div>
この状態で slick()
を発火しても意味がないということだ。
これをどうにかしたい。
ずさんな解決方法
つまり、全てのElementが用意された時点で slick()
を発火してやれば良い。
export default Vue.extend({ data() { return { elements: [], isSlicked: false } }, methods: { async getElements(){ await HTTP.get('/api/elements').map(x => Element.new(x)) } }, async created() { this.elements = await getElements() }, watch: { elements(vals, oldVals) { if (!this.isSlicked) return; $('.is-slick').slick('unslick') this.isSlicked = false } } updated() { if(!this.isSliced) { $('.is-slick').slick() } /** 2018/02/16 11時05分 更新 this.$nextTick(() => { try { // 既に slick() してあるElementに対してもう一度発火すると落ちる。 // 逆に、まだ slick() していないElementに対して `unslick` を発火しても落ちる。 // ほんに〜〜〜〜〜????????? $('.is-slick').slick('unslick') } catch(_){ } finally { $('.is-slick').slick() } */ }) } })
updated
で $nextTick()
を使うと全てのRenderが完了してから呼ばれる。
これで解決したけど、ずさんすぎる気がする。
たぶんComponentのライフサイクルの設計が間違っているんだと思う。
誰か良さげな回避策を教えて……ください……
- そもそも
slick
を利用しないという選択 - カルーセルくらい自前で作れるだろ感
- etc...