vue

Vue学习笔记(十九)之Vue中多个元素或组件的过渡

Posted by weite122 on 2018-09-22

多个元素的过渡

  • 对于原生标签可以使用 v-if/v-else 。需要注意的是当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 <transition> 组件中的多个元素设置 key 是一个更好的实践。
  • 在多个元素同时进入和离开过渡的时候,动画会混乱,可以用过渡模式避免这个问题。
    • in-out: 新元素先进行过渡,完成之后当前元素过渡离开
    • out-in: 当元素先进行过渡,完成之后新元素过渡进入
  • Demo
  • 代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Vue中多个元素或组件的过渡</title>
    <script src="http://vuejs.org/js/vue.js"></script>
    <style>
    .v-enter,
    .v-leave-to {
    opacity: 0;
    }
    .v-enter-active,
    .v-leave-active {
    transition: opacity .5s;
    }
    </style>
    </head>
    <body>
    <div id="root">
    <transition mode="out-in">
    <div v-if="show" key="Hello">Hello World</div>
    <div v-else key="Bye">Bye World</div>
    </transition>
    <button @click="handleClick">Toggle</button>
    </div>
    <script>
    var vm = new Vue({
    el: '#root',
    data: {
    show: true
    },
    methods: {
    handleClick: function () {
    this.show = !this.show
    }
    }
    })
    </script>
    </body>
    </html>

多个组件过渡

  • 多个组件只需要动态组件切换即可,不需要key特性。
  • Demo
  • 代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Vue中多个元素或组件的过渡</title>
    <script src="http://vuejs.org/js/vue.js"></script>
    <style>
    .v-enter,
    .v-leave-to {
    opacity: 0;
    }
    .v-enter-active,
    .v-leave-active {
    transition: opacity .5s;
    }
    </style>
    </head>
    <body>
    <div id="root">
    <transition mode="out-in">
    <component :is="type"></component>
    </transition>
    <button @click="handleClick">Toggle</button>
    </div>
    <script>
    Vue.component('child-one', {
    template: '<div>Child-One</div>'
    })
    Vue.component('child-two', {
    template: '<div>Child-Two</div>'
    })
    var vm = new Vue({
    el: '#root',
    data: {
    type: 'child-one'
    },
    methods: {
    handleClick: function () {
    this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
    }
    }
    })
    </script>
    </body>
    </html>

列表过渡

  • 列表过渡需要使用<transition-group>组件,它的特点:
    • 不同于 <transition>,它会以一个真实元素呈现:默认为一个 <span>。你也可以通过 tag 特性更换为其他元素。
    • 过渡模式不可用,因为我们不再相互切换特有的元素。
    • 内部元素 总是需要 提供唯一的 key 属性值。
  • Demo
  • 代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>列表过渡</title>
    <script src="http://vuejs.org/js/vue.js"></script>
    <style>
    .list-complete-enter, .list-complete-leave-to {
    opacity: 0;
    transform: translateY(30px);
    }
    .item {
    transition: all 1s;
    display: inline-block;
    margin-right: 10px;
    }
    </style>
    </head>
    <body>
    <div id="root">
    <button @click="add">Add</button>
    <button @click="remove">Remove</button>
    <transition-group mode="out-in" name="list-complete" tag="p">
    <span v-for="item of list" :key="item" class="item">{{item}}</span>
    </transition-group>
    </div>
    <script>

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

封装动画

  • 将动画效果都封装到一个组件,其他组件使用时直接调用
  • Demo
  • 代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>封装动画</title>
    <script src="http://vuejs.org/js/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
    </head>
    <body>
    <div id="root">
    <fade :show="show">
    <div>Hello World</div>
    </fade>

    <fade :show="show">
    <h1>Bye World</h1>
    </fade>
    <button @click="handleClick">Toggle</button>
    </div>
    <script>
    Vue.component('fade', {
    props: ['show'],
    template: `
    <transition @before-enter="handleBeforeEnter"
    @enter="handleEnter"
    @after-enter="hanldeAfterEnter">
    <slot v-if="show"></slot>
    </transition>`,
    methods: {
    handleBeforeEnter: function (el) {
    el.style.opacity = 0
    el.style.transformOrigin = 'left'
    },
    handleEnter: function (el, done) {
    el.textContent = 'Animation Start'
    Velocity(el, {opacity: 1, fontSize: '1.5em'}, {duration: '300'})
    Velocity(el, {fontSize: '1em'}, {complete: done})
    },
    hanldeAfterEnter: function (el) {
    el.textContent = 'Animation End'
    }
    }

    })

    var vm = new Vue({
    el: '#root',
    data: {
    show: true
    },
    methods: {
    handleClick: function () {
    this.show = !this.show
    }
    }
    })
    </script>
    </body>
    </html>