# CH6 トランジションとアニメーション
# S28 トランジションとは
194~197ページ
# 基本的なトランジションの使い方
195ページ
「スタイルを定義して動かしてみよう」もまとめています。
<div id="app">
<p><button v-on:click="show=!show">切り替え</button></p>
<transition>
<div v-show="show">
トランジションさせたい要素
</div>
</transition>
</div>
new Vue({
el: '#app',
data: {
show: true
}
})
/* 1秒かけて透明度を遷移 */
.v-enter-active, .v-leave-active {
transition: opacity 1s;
}
/* 見えなくなるときの透明度 */
.v-enter, .v-leave-to {
opacity: 0;
}
トランジションさせたい要素
# S29 単一要素トランジション
# EnterとLeaveで別々のスタイルを定義
201ページ
.v-enter-active,
.v-leave-active {
transition: opacity 1s, transform 1s;
}
/* 表示するときは左から */
.v-enter {
opacity: 0;
transform: translateX(-10px);
}
/* 消えるときは下へ */
.v-leave-to {
opacity: 0;
transform: translateY(10px);
}
# 複数の要素をグループ化する
202ページ
<div id="app">
<p><button v-on:click="show=!show">切り替え</button></p>
<transition>
<div v-if="show" key="a">TRUE</div>
<div v-else key="b">FALSE</div>
</transition>
</div>
new Vue({
el: '#app',
data: {
show: true
}
})
.v-enter-active, .v-leave-active {
transition: opacity 1s;
}
.v-enter, .v-leave-to {
opacity: 0;
}
.v-enter-active, .v-leave-active {
transition: opacity 1s;
}
.v-leave-active {
position: absolute;
}
.v-enter, .v-leave-to {
opacity: 0;
}
へんな感じのスタイル
TRUE
いい感じのスタイル
TRUE
# EnterとLeaveのタイミングを変更する
203ページ
※ position: absolute
は指定していない。
normal
TRUE
out-in
TRUE
in-out
TRUE
# キーの変化によるトランジションの発動
204ページ
<div id="app">
<p><button v-on:click="count++">切り替え</button></p>
<transition>
<div v-bind:key="count">{{ count }}</div>
</transition>
</div>
new Vue({
el: '#app',
data: {
count: 0
}
})
.v-enter-active {
transition: opacity 1s;
}
/* 微妙に時間をずらして文字色の濃度を調整してます */
.v-leave-active {
transition: opacity 0.8s ease 0.2s;
position: absolute;
}
.v-enter, .v-leave-to {
opacity: 0;
}
0
# S30 リストトランジション
206~209ページ
# 移動トランジション
206ページ
このサンプルコードでは Lodash を使用しています。「lodash.min.js」を読み込んでください。
<div id="app">
<p><button v-on:click="order=!order">切り替え</button></p>
<!-- transition-groupタグに指定した属性はラップ要素に付与される -->
<transition-group tag="ul" class="list">
<li v-for="item in sortedList" v-bind:key="item.id">
{{ item.name }} {{ item.price }}円
</li>
</transition-group>
</div>
new Vue({
el: '#app',
data: {
order: false,
list: [
{ id: 1, name: 'りんご', price: 100 },
{ id: 2, name: 'ばなな', price: 200 },
{ id: 3, name: 'いちご', price: 300 }
]
},
computed: {
// orderの値でリストの順番を反転する算出プロパティ
sortedList: function () {
// LodashのorderByメソッドを使用
return _.orderBy(this.list, 'price', this.order ? 'desc' : 'asc')
}
}
})
/* 1秒かけて要素を移動させる */
.v-move {
transition: transform 1s;
}
- りんご 100円
- ばなな 200円
- いちご 300円
# 移動トランジション X&Y座標
207ページ
要素の追加&削除機能も付けています。
このサンプルコードでは Lodash を使用しています。「lodash.min.js」を読み込んでください。
<div id="app">
<p>
<button v-on:click="doShuffle">シャッフル</button>
<button v-on:click="doAdd">追加</button>
</p>
<transition-group tag="ul" class="list">
<li v-for="(item, index) in list"
v-bind:key="item"
class="item"
v-on:click="doRemove(index)">{{ item }}</li>
</transition-group>
</div>
new Vue({
el: '#app',
data: {
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
},
methods: {
doShuffle: function () {
this.list = _.shuffle(this.list)
},
doAdd: function() {
var newNumber = Math.max.apply(null, this.list) + 1
var index = Math.floor(Math.random() * (this.list.length + 1))
this.list.splice(index, 0, newNumber)
},
doRemove: function (index) {
this.list.splice(index, 1)
}
}
})
/* 以下はボックス要素のスタイル */
.list {
width: 240px;
padding: 0;
}
.item {
display: inline-flex;
justify-content: center;
align-items: center;
margin: 4px;
width: 40px;
height: 40px;
background: #f5f5f5;
}
/* トランジション用スタイル */
.v-enter-active, .v-leave-active, .v-move {
transition: all 1s;
}
.v-leave-active {
position: absolute;
}
.v-enter, .v-leave-to {
opacity: 0;
background: #f9a3b1;
transform: translateY(-30px);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
TIP
親要素が Flexbox だったり、要素の位置によって Leave 時の座標がおかしくなり、あさっての方向に飛んでいくことがあります。 次のデモは、フックを使って位置を補正したものです。左端の要素が消えるときの動きに違いがあります。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
このあとの「トランジションフック」のセクションにコードを載せています。
# S31 SVGのトランジション
210~211ページ
# SVGをトランジションで切り替えよう
210ページ
<div id="app">
<button v-on:click="toggle=!toggle">切り替え</button>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<!-- SVGのパーツにトランジションを適用 -->
<transition>
<my-circle v-bind:fill="fill" v-bind:key="fill"></my-circle>
</transition>
</svg>
</div>
// SVGパーツのコンポーネントを定義
Vue.component('my-circle', {
template: '<circle cx="80" cy="75" r="50" v-bind:fill="fill"/>',
props: {
fill: String
}
})
new Vue({
el: '#app',
data: {
toggle: false
},
computed: {
fill: function () {
return this.toggle ? 'lightpink' : 'skyblue'
}
}
})
.v-enter-active, .v-leave-active {
transition: all 1s;
}
.v-leave-active {
position: absolute;
}
.v-enter, .v-leave-to {
opacity: 0;
transform: translateX(-20px);
}
※ 古いブラウザでは動作しない場合があります。
# S32 トランジションフック
212~213ページ
# 使用できるトランジションフック
212ページ
すべてのタイミングにフックした場合。
<div id="app">
<p><button v-on:click="show=!show">切り替え</button></p>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled">
<div v-if="show">example</div>
</transition>
</div>
new Vue({
el: '#app',
data: {
show: true
},
methods: {
// Enter
beforeEnter: function (el) {
console.log('before-enter')
},
enter: function (el, done) {
console.log('enter')
setTimeout(done, 1000)
},
afterEnter: function (el) {
console.log('after-enter')
},
enterCancelled: function (el) {
console.log('enter-cancelled')
},
// Leave
beforeLeave: function (el) {
console.log('before-leave')
},
leave: function (el, done) {
console.log('leave')
setTimeout(done, 1000)
},
afterLeave: function (el) {
console.log('after-leave')
},
// v-show と共に使うときだけ leaveCancelled は有効です
leaveCancelled: function (el) {
console.log('leave-cancelled')
}
}
})
.v-enter-active, .v-leave-active {
transition: all 1s;
}
.v-enter, .v-leave-to {
opacity: 0;
transform: translateX(-20px);
}
※ コンソールにログが表示されます
example
# Leave 時の位置補正
移動トランジション X&Y座標 のコードに、次のような before-leave
へのフックを追加して位置を補正することで、あさっての方向に飛んでいくのを回避できます。
<transition-group tag="ul" class="list" v-on:before-leave="beforeLeave">
...
</transition-group>
methods: {
beforeLeave: function (el) {
var style = window.getComputedStyle(el)
el.style.left = el.offsetLeft - parseFloat(style.marginLeft, 10) + 'px'
el.style.top = el.offsetTop - parseFloat(style.marginTop, 10) + 'px'
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8