Vue之過渡動畫(一)

3.1、進入/離開 & 列表過渡

1. Overview

  1. Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM.
  2. On this page, we’ll only cover **entering, leaving, **and list transitions, but you can see the next section for managing state transitions.

DOM操作時的過渡效果,讓頁面更絲滑。

2. 單元素/組件的過渡

先來個demo開開胃,完整代碼

<style>
  .fade-enter-active, .fade-leave-active {
    transition: opacity .5s;
  }
  .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
    opacity: 0;
  }
</style>

<div id="demo">
    <button v-on:click="show = !show">
        Toggle
    </button>
    <transition name="fade">
        <p v-if="show">hello</p>
    </transition>
</div>

<script>
    new Vue({
        el: '#demo',
        data: {
            show: true
        }
    })
</script>

2.1 過渡的類名(Transition Classes)

There are six classes applied for enter/leave transitions.

enter/leave過渡中,會有6個class切換

  • v-enter
  • v-enter-active
  • v-enter-to (2.1.8+)
  • v-leave
  • v-leave-active
  • v-leave-to (2.1.8+)

在這裏插入圖片描述

2.2 CSS過渡

即給上面例子中的 .fade-enter-active, .fade-leave-active 這些類名應用的CSS樣式

2.3 CSS動畫

寫法差不多,就是把transition換成animation 完整代碼

<style>
  .bounce-enter-active {
    animation: bounce-in .5s;
  }

  .bounce-leave-active {
    animation: bounce-in .5s reverse;
  }

  @keyframes bounce-in {
    0% {
      transform: scale(0);
    }
    50% {
      transform: scale(1.5);
    }
    100% {
      transform: scale(1);
    }
  }
</style>

<div id="example-2">
  <button @click="show = !show">Toggle show</button>
  <transition name="bounce">
    <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p>
  </transition>
</div>
<script>
    new Vue({
        el: '#example-2',
        data: {
            show: true
        }
    })
</script>


2.4 自定義過渡的類名

我們可以通過以下 attribute 來自定義過渡類名:

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+)

如下與 Animate.css的結合使用:完整代碼

<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">

<div id="example-3">
  <button @click="show = !show">
    Toggle render
  </button>
  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>
</div>

<script>
  new Vue({
    el: '#example-3',
    data: {
      show: true
    }
  })
</script>

2.5 同時使用過渡和動畫

要同時使用過渡和動畫,要用type屬性指明類型:animation or transition

2.6 指定過渡的時間

<transition :duration="1000">...</transition>
<transition :duration="{ enter: 500, leave: 800 }">...</transition>

2.7 JavaScript鉤子(JavaScript Hooks)

用js代碼操作動畫
如下使用了Velocity.js動畫庫,完整代碼

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>

<div id="example-4">
  <button @click="show = !show">
    Toggle
  </button>
  <transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show">
      Demo
    </p>
  </transition>
</div>

<script>
    new Vue({
        el: '#example-4',
        data: {
            show: false
        },
        methods: {
            beforeEnter: function (el) {
                el.style.opacity = 0
                el.style.transformOrigin = 'left'
            },
            enter: function (el, done) {
                Velocity(el, {opacity: 1, fontSize: '1.4em'}, {duration: 300})
                Velocity(el, {fontSize: '1em'}, {complete: done})
            },
            leave: function (el, done) {
                Velocity(el, {translateX: '15px', rotateZ: '50deg'}, {duration: 600})
                Velocity(el, {rotateZ: '100deg'}, {loop: 2})
                Velocity(el, {
                    rotateZ: '45deg',
                    translateY: '30px',
                    translateX: '30px',
                    opacity: 0
                }, {complete: done})
            }
        }
    })
</script>

3. 初始渲染的過渡(Transitions on Initial Render)

If you also want to apply a transition on the initial render of a node, you can add the appear attribute:

一個DOM節點初始化渲染到頁面時可以引用過渡效果

<transition appear>
  <!-- ... -->
</transition>

// 【還自定義class】
<transition
  appear
  appear-class="custom-appear-class"
  appear-to-class="custom-appear-to-class" (2.1.8+)
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>

// 【也可以自定義js鉤子】
<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>

4. 多個元素之間的過渡(Transitioning Between Elements)

一個常見的場景就是:渲染列表元素時,如果列表是空的,則渲染一個代表空列表的元素

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>

需要注意:如果兩個tag名一樣的元素之間做過渡時,要加key demo如下:

<style>
  .bounce-enter-active {
    animation: bounce-in .5s;
  }

  .bounce-leave-active {
    animation: bounce-in .5s reverse;
  }

  @keyframes bounce-in {
    0% {
      transform: scale(0);
    }
    50% {
      transform: scale(1.5);
    }
    100% {
      transform: scale(1);
    }
  }
</style>
<div id="app">
    <transition name="bounce">
        <button v-bind:key="docState">
            {{ buttonMessage }}
        </button>
    </transition>
    <button @click="savebutton">切換按鈕</button>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            docState: 'saved'
        },
        computed:{
            buttonMessage: function () {
                switch (this.docState) {
                    case 'saved': return 'Edit'
                    case 'edited': return 'Save'
                }
            }
        },
        methods: {
            savebutton:function () {
                if(this.docState == 'edited'){
                    this.docState = 'saved'
                }else {
                    this.docState = 'edited'
                }

            }
        }
    })
</script>

完整代碼

4.1 過渡模式

可以設置兩種過渡模式:

  • in-out: New element transitions in first, then when complete, the current element transitions out.

  • out-in: Current element transitions out first, then when complete, the new element transitions in.

我們來對比下設置了out-in模式和不設置的區別吧:給上面例子上的transition加上mode屬性爲out-in

 <transition name="bounce" mode="out-in">
   <button v-bind:key="docState">
     {{ buttonMessage }}
   </button>
 </transition>

加之前:
在這裏插入圖片描述
加之後:效果棒棒噠
在這裏插入圖片描述

5. 多個組件之間的過渡

組件之間的過渡更加簡單,寫法和元素一樣,不需要加key

<style>
  .component-fade-enter-active, .component-fade-leave-active {
    transition: opacity .3s ease;
  }
  .component-fade-enter, .component-fade-leave-to
  /* .component-fade-leave-active below version 2.1.8 */ {
    opacity: 0;
  }
</style>

<div id="app">
    <input type="radio" value="v-a" id="a" name="view" @change="view='v-a'">
    <label for="a">A</label>

    <input type="radio" value="v-b" id="b" name="view" @change="view='v-b'">
    <label for="b">B</label>
    <transition name="component-fade" mode="out-in">
        <component v-bind:is="view"></component>
    </transition>
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            view: 'v-a'
        },
        components: {
            'v-a': {
                template: '<div>Component A</div>'
            },
            'v-b': {
                template: '<div>Component B</div>'
            }
        }
    })
</script>

完整代碼

6. 列表過渡(List Transitions)

列表的Entering/Leaving過渡、Move Transitions移動過渡,用<transition-group>
有幾個注意點:

  • 渲染時會轉換爲實際元素,默認爲span,可以加tag標籤指定,如下例子中指定爲 tag='p'
  • 的內部元素上要加key
  • css過渡類是應用在內部元素上的,而不是 group/container itself.

6.1 List Entering/Leaving Transitions

<style>
  .list-complete-item {
    transition: all 1s;
    display: inline-block;
    margin-right: 10px;
  }

  .list-complete-enter, .list-complete-leave-to
  /* .list-complete-leave-active below version 2.1.8 */ {
    opacity: 0;
    transform: translateY(30px);
  }
  .list-complete-leave-active {
    position: absolute;
  }
</style>

<div id="list-demo">
    <button v-on:click="shuffle">Shuffle</button>
    <button v-on:click="add">Add</button>
    <button v-on:click="remove">Remove</button>

    <transition-group name="list-complete" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-complete-item">
      {{ item }}
    </span>
    </transition-group>
</div>

<script>
    new Vue({
        el: '#list-demo',
        data: {
            items: [1, 2, 3, 4, 5, 6, 7, 8, 9],
            nextNum: 10
        },
        methods: {
            randomIndex: function () {
                return Math.floor(Math.random() * this.items.length)
            },
            add: function () {
                this.items.splice(this.randomIndex(), 0, this.nextNum++)
            },
            remove: function () {
                this.items.splice(this.randomIndex(), 1)
            },
            shuffle: function () {
                this.items = _.shuffle(this.items)
            }
        }
    })
</script>

完整代碼

6.2 List Move Transitions

上面演示了列表內元素進入/離開時的過渡效果,
爲了列表中元素移動時的過渡效果,vue引入了v-move過渡類名,如下的:.flip-list-move

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<style>
	.flip-list-move {
  	transition: transform 1s;
	}
</style>
<div id="flip-list-demo" class="demo">
  <button v-on:click="shuffle">Shuffle</button>
  <transition-group name="flip-list" tag="ul">
    <li v-for="item in items" v-bind:key="item">
      {{ item }}
    </li>
  </transition-group>
</div>

<script>
  new Vue({
    el: '#flip-list-demo',
    data: {
      items: [1,2,3,4,5,6,7,8,9]
    },
    methods: {
      shuffle: function () {
        this.items = _.shuffle(this.items)
      }
    }
  })
</script>

完整代碼

6.3 列表使用Javascript鉤子函數添加過渡效果

上面講的都是列表用css進行過渡,列表也可以用js代碼進行過渡,如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>

<div id="staggered-list-demo">
    <input v-model="query">
    <transition-group
            name="staggered-fade"
            tag="ul"
            v-bind:css="false"
            v-on:before-enter="beforeEnter"
            v-on:enter="enter"
            v-on:leave="leave"
    >
        <li
                v-for="(item, index) in computedList"
                v-bind:key="item.msg"
                v-bind:data-index="index"
        >{{ item.msg }}
        </li>
    </transition-group>
</div>

<script>
    new Vue({
        el: '#staggered-list-demo',
        data: {
            query: '',
            list: [
                { msg: 'Bruce Lee' },
                { msg: 'Jackie Chan' },
                { msg: 'Chuck Norris' },
                { msg: 'Jet Li' },
                { msg: 'Kung Fury' }
            ]
        },
        computed: {
            computedList: function () {
                var vm = this
                return this.list.filter(function (item) {
                    return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
                })
            }
        },
        methods: {
            beforeEnter: function (el) {
                el.style.opacity = 0
                el.style.height = 0
            },
            enter: function (el, done) {
                var delay = el.dataset.index * 150
                setTimeout(function () {
                    Velocity(
                        el,
                        { opacity: 1, height: '1.6em' },
                        { complete: done }
                    )
                }, delay)
            },
            leave: function (el, done) {
                var delay = el.dataset.index * 150
                setTimeout(function () {
                    Velocity(
                        el,
                        { opacity: 0, height: 0 },
                        { complete: done }
                    )
                }, delay)
            }
        }
    })
</script>

完整代碼

7. 可複用的過渡

To create a reusable transition, all you have to do is place a <transition> or <transition-group>

組件的過渡也也可以不用,相當於一個殼子,殼子上帶着過渡效果,你可以複用到別的地方

8. 動態過渡

Yes, even transitions in Vue are data-driven! The most basic example of a dynamic transition binds the name attribute to a dynamic property.

由於過渡效果的實現都是在<transition> or <transition-group> 組件上添加屬性,那麼這些屬性的屬性值根據不同條件也可以被指定不同的動態值。
這就是動態過渡的由來。讓過渡更加靈活和隨心所欲

更多Vue文檔解讀:《Vue Doc 筆記》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章