Vue.js transition-group
by uto usui
HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div id="app">
<div class="field has-addons">
<p class="control">
<button class="button" @click="toggle">
{{show ? 'leave' : 'enter'}}
</button>
</p>
<p class="control">
<button class="button" @click="add">
add
</button>
</p>
<p class="control">
<button class="button" @click="shuffle">
shuffle
</button>
</p>
</div>
<div class="field">
<label class="label">Image Query</label>
<div class="control">
<input class="input" type="text" placeholder="Text input" v-model="query">
</div>
<p class="help is-info">Enter the keyword of the image you want to call.</p>
</div>
<transition-group name="fade" tag="ul" class="columns is-mobile is-multiline is-gapless">
<li class="column is-one-third" v-show="show" v-for="item in items" :key="item.src">
<img :src="item.src" alt="placeholder">
</li>
</transition-group>
</div>
SCSS
// 位置の変化を検知する *-move
.fade-move {
transition: all 1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
}
// enter の活性状態。トランジションに入るフェーズ中に適用。
// 要素が挿入される前に追加され、トランジション/アニメーションが終了すると削除
// 期間、遅延、およびイージングカーブを定義
.fade-enter-active {
// easeOutExpo
transition: all 1s cubic-bezier(0.19, 1, 0.22, 1);
}
// leave の活性状態。トランジションが終わるフェーズ中に適用
// leave トランジションがトリガされるとき、直ちに追加され、トランジション/アニメーションが終了すると削除
// 期間、遅延、およびイージングカーブを定義
.fade-leave-active {
// easeInQuart
transition: all 1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
}
// enter の開始状態。要素が挿入される前に適用され、要素が挿入された 1 フレーム後に削除
.fade-enter {
opacity: 0;
transform: translateX(-100%);
}
// leave の終了状態
// トランジションの終了がトリガされた後に (同時に v-leave 削除) 1フレーム追加
// トランジション/アニメーションが終了すると削除
.fade-leave-to {
opacity: 0;
transform: translateX(100%);
}
img {
vertical-align: bottom;
}
Babel + JSX
let baseImageUrl = 'https://source.unsplash.com/1600x900/?';
const root = new Vue({
data: function() {
return {
show: false,
items: [
{
id: this.counter,
src: baseImageUrl + 'nature,water'
},
],
query: '',
counter: 0,
}
},
methods: {
toggle() {
this.show = !this.show
},
add() {
// 画像ロードするの待って
let img = new Image();
let src = baseImageUrl + this.query;
img.onload = () => {
this.items.push({
src: src
});
};
img.src = src;
},
shuffle() {
this.items = _.shuffle(this.items)
}
}
});
root.$mount( '#app' );