第4章 Vue 过渡和动画

第4章 Vue 过渡和动画

4.1 过渡和动画基础

transition 组件

注 意   t r a n s i t i o n   同 一 时 间 只 能 显 示 一 个 元 素 注意\ transition\ 同一时间只能显示一个元素  transition 

把需要添加过渡的 div 放入其中,用 name 设置前缀(默认前缀是 v)

<transition name='box'>
	<div class='chart' v-if='isShow'></div>
</transition>

初始状态

<style>
    .chart {
        width: 200px;
        height: 50px;
        background-color: orangered;
    }
    .box-enter-active, .box-leave-active {
        transition: width 3s;
    }
    .box-enter, .box-leave-to {
        width: 0px;
    }
    .box-enter-to, .box-leave {
        width: 200px;
    }
</style>

自定义类名

通 过 属 性 来 设 置 ( 自 定 义 类 名 结 合   a n i m a t e . c s s   动 画 库 ) 通过属性来设置(自定义类名结合\ animate.css\ 动画库)  animate.css 

<transition enter-active-class='animated bounceInLeft'
    leave-active-class='animated bounceOutLeft'>
    <p v-if='isShow'>hello world</p>
</transition>

a p p e a r   初 始 渲 染 动 画 ( 每 次 刷 新 页 面 ) appear\ 初始渲染动画(每次刷新页面) appear 

<link rel="stylesheet" href="animate.css">
<transition appear appear-class='animated swing'
appear-to-class='animated bounceIn'
appear-active-class='animated bounceOut'>
    <div v-if='isShow's>过渡文字</div>
</transition>

使用@keyframes 创建 CSS 动画

动 画 和 过 渡 的 区 别 就 在 于 , 动 画 可 以 改 中 间 内 容 , 一 帧 一 帧 的 改 动画和过渡的区别就在于,动画可以改中间内容,一帧一帧的改

<style>
    /* .bounce */
    .box-enter-active {         
        animation: Ami 2.5s;	/* 动画时间 */
    }
    .box-leave-active {
        animation: Ami 2.5s;
    }
    @keyframes Ami {
        0% {transform: scale(0); background: orangered;}
        20% {transform: scale(1); background: burlywood;}
        40% {transform: scale(1.25); background: blue;}
        60% {transform: scale(1.3); background: burlywood;}
        80% {transform: scale(1.25); background: orangered;}
        100% {transform: scale(1); background: orange;}
    }

Vue 结合 Velocity.js 实现动画

用 了 钩 子 函 数 和   V e l o c i t y . j s 用了钩子函数 和\ Velocity.js  Velocity.js

<script src="velocity.js"></script>

<transition @before-enter='beforeEnter' @enter='enter' 
@leave='leave' v-bind:css='false'>
    <p v-if='isShow'>demo 05</p>
</transition>

<script>
methods: {
    beforeEnter(el) {
        el.style.opacity = 0
        el.style.transformOrigin = 'left'    // 旋转元素的基点位置
        el.style.color = 'red'
    },
    enter(el, done) {
        Velocity(el, {opacity: 1, fontSize: '1.4em'}, {duration: 300})  // duration 执行时间
        Velocity(el, {fontSize: '1em'}, {complete: done})
    },
    leave(el, done) {
        Velocity(el, {translateX: '15px', rotateZ: '50deg'}, {duration: 3000})
        Velocity(el, {rotateZ: '100deg'}, {loop: 2})    // 重复 2 次
        Velocity(el, {rotateZ: '45deg', translateY: '30px', translateX: '30px',
            opacity: 0}, {complete: done})
    }
}	// 哦,天爷,自己琢磨吧。。(这个 velocity 用的是老版本的)

使 Vue 跳过 CSS 的检测

v-bind:css="false"

4.2 多个元素过渡

不同签名元素的过渡

用   v − i f   和   v − e l s e 用\ v-if\ 和\ v-else  vif  velse

<transition>
    <div v-if='1 > 0'>div</div>
    <p v-else>p</p>
</transition>

相同签名元素的过渡

需 要   k e y , 不 然 无 法 区 分 相 同 签 名 的 元 素 需要\ key,不然无法区分相同签名的元素  key

<button @click='isShow = !isShow'>change isShow</button>
<transition name='fade'>
    <button v-if='isShow' key='save'>save</button>
    <button v-else key='edit'>edit</button>
</transition>

通 过 改   k e y   的 值 , 实 现 按 钮 切 换 通过改\ key\ 的值,实现 按钮切换  key 

<button v-bind:key='isShow'>{{isShow ? 'true' : 'false'}} </button>

还 可 以 这 样 用   v − i f 还可以这样用\ v-if  vif

<div class="red" v-if="show == 'A'" key="A"></div>
<div class="blue" v-if="show == 'B'" key="B"></div>
<div class="yellow" v-if="show == 'C'" key="C"></div>
<script>
    showNum () {
        if (this.show == 'A') { return this.show = 'B' }
    } // 切换 show

还 可 以 用   c o m p u t e d   计 算 属 性 还可以用\ computed\ 计算属性  computed 

{{showNum}}
computed: {
    showNum() {
        switch(this.isShow) {
            case 'A': return 'a'
// 不再赘述

过渡模式

为 实 现 有 序 过 渡 , 加 了   m o d e   属 性 为实现有序过渡,加了\ mode\ 属性  mode 

mode 属性有两个值:in-out 和 out-in,一般用 out-in,先出后进(即当前元素先过渡,然后新元素过渡进入)
<transition name='fade' mode='out-in'>
    <button v-bind:key='isOff' @click='isOff = !isOff'>
        {{isOff ? 'Off' : 'On'}}
    </button>
</transition>
// 用了 mode 和 out-in 以后,很丝滑

4.3 多个组件过渡

不 需 要 用   k e y   特 性 , 用 动 态 组 件 即 可 ( 即   i s   属 性 ) 不需要用\ key\ 特性,用动态组件即可(即\ is\ 属性)  key  is 

// 主要就是用的 is 切换的组件
<style>
    .fade-enter-active, .fade-leave-active {
        transition: opacity .5s ease;
    }
    .fade-enter, .fade-leave-to {
        opacity: 0;
    }
</style>
<body>
    <div id='app'>
        <a href="javascript:;" @click='compontentName="example1"'>login</a>
        <a href="javascript:;" @click='compontentName="example2"'>register</a>
        <transition name='fade' mode='in-out'>
            <component v-bind:is='compontentName'></component>
        </transition>
    </div>
    <template id='ex1'> <span>login component</span> </template>
    <template id='ex2'> <span>register component</span> </template>
    <script>
        Vue.component('example1', {template: '#ex1'})
        Vue.component('example2', {template: '#ex2'})
        var vm = new Vue({
            el: '#app',
            data: { compontentName: '' }
        })
    </script>
</body>

4.4 列表过渡

前面的都是 渲染单个元素或同时渲染多个元素中的一个,不适用于列表过渡

列表的进入和离开过渡

列 表 过 渡 用   v − f o r   和   t r a n s i t i o n − g r o u p 列表过渡用\ v-for\ 和\ transition-group  vfor  transitiongroup

.list-item {
    display: inline-block; margin-right: 10px; background-color: orangered;
    border-radius: 50%; width: 25px; height: 25px; text-align: center;
    line-height: 25px; color: #fff;
}
.list-enter-active, .list-leave-active {
    transition: all 1s;
}
.list-enter, .list-leave-to {
    opacity: 0;
    transform: translateY(30px)
}

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

data: {
    items: [1, 2, 3, 4, 5],
    nextNum: 6
},
methods: {
    randomIndex() {
        return Math.floor(Math.random() * this.items.length)    // 0-1 之间的随机数
    },
    add() {
        this.items.splice(this.randomIndex(), 0, this.nextNum++)    // 删除 0 个
    },
    remove() {
        this.items.splice(this.randomIndex(), 1)
    }
}

列表的排序过渡

为 了 实 现 平 滑 过 渡 , 用   v − m o v e   ( V u e   采 用 了   F L I P   技 术 , 动 画 更 流 畅 ) 为了实现平滑过渡,用\ v-move\ (Vue\ 采用了\ FLIP\ 技术,动画更流畅)  vmove (Vue  FLIP )

.list-leave-active {
    transition: all 1s;
    position: absolute;		// leave 这里要加一个绝对定位,否则不平滑
}
.list-move {
    transition: transform 1s;
}
  • 效果图:
test

利用 lodash.js 实现洗牌功能

<script src="lodash.js"></script>

<script>
shuffle() {
    this.items = _.shuffle(this.items)
}
  • 效果图:
test2

列表的交错过渡

钩 子 函 数 结 合   V e l o c i t y . j s   实 现 搜 索 功 能 钩子函数结合\ Velocity.js\ 实现搜索功能  Velocity.js 

<input type="text" placeholder="please enter what you are looking for:" v-model='query'>
<transition-group name='item' tag='ul' @before-enter='beforeEnter' @enter='enter'
@leave='leave' :css='false'>
    <li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
        {{item.msg}}
    </li>
</transition-group>

<script>
data: {
    query: '',
    items: [
        {msg: 'zhangsan'}, {msg: 'lisi'}, {msg: 'zhangfangfang'},
        {msg: 'wanglinlin'}, {msg: 'fengyuan'}
    ]
},
computed: {
    ComputedList() {
        var content = this.query
        var nameList = this.items
        return nameList.filter(function (item) {
            return item.msg.toLowerCase().indexOf(content.toLowerCase()) !== -1
        })		// 利用计算属性 返回过滤后的列表(研究下这个 return)
    }
},
methods: {
    beforeEnter(el) {
        el.style.opacity = 0
        el.style.height = 0
    },
    enter(el, done) {
        var delay = el.dataset.index * 150
        setTimeout(function() {
            Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
        }, delay)
    },
    leave(el, done) {
        var delay = el.dataset.index * 150
        setTimeout(function() {
            Velocity(el, {opacity: 0, height: 0}, {complete: done})
        }, delay)
    }
}
// 这样看来,写的时候可以只用三个钩子函数,就可以把进出的过渡写完(无 css 参与,用的 Velocity.js)
// 还是用 css 吧,只需给 v-enter-active & v-leave-active 写个 transition,
// 以及给 v-enter & v-leave-to 写个 opacity 即可
  • 效果图:
test

可复用的过渡

t e m p l a t e   方 式 实 现 过 渡 的 封 装 template\ 方式实现过渡的封装 template 

就是写组件模板里面,用插件 slot 显示列表

<fade :query='query' :items='items'>
    <li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
        {{item.msg}}
    </li>
</fade>

<template id="temp">
    <transition-group name='item' tag='ul' @before-enter='beforeEnter' @enter='enter'
    @leave='leave' :css='false'>
        <!-- <li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
            {{item.msg}}
        </li> 用 slot -->
        <slot></slot>
    </transition-group>
</template>

<script>
Vue.component('fade', {
    props: ['query', 'items'],
    template: '#temp',
    methods: {
        beforeEnter(el) {
            el.style.opacity = 0
            el.style.height = 0
        },
        enter(el, done) {
            var delay = el.dataset.index * 150
            setTimeout(function() {
                Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
            }, delay)
        },
        leave(el, done) {
            var delay = el.dataset.index * 150
            setTimeout(function() {
                Velocity(el, {opacity: 0, height: 0}, {complete: done})
            }, delay)
        }
    }
})

函 数 式 组 件 方 式 , 就 是 用   r a n d e r   函 数 来 实 现 函数式组件方式,就是用\ rander\ 函数来实现  rander 

改一下 script 的内容为如下即可,效果如前(用了 render)

<script>
Vue.component('fade', {
    functional: true,       // 标记 fade 组件为函数式组件
    props: ['query', 'items'],
    render(h, ctx) {
        var data = {
            props: {
                tag: 'ul',      // 默认 span
                css: false
            },
            on: {
                beforeEnter(el) {
                    el.style.opacity = 0
                    el.style.height = 0
                },
                enter(el, done) {
                    var delay = el.dataset.index * 150
                    setTimeout(function() {
                        Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
                    }, delay)
                },
                leave(el, done) {
                    var delay = el.dataset.index * 150
                    setTimeout(function() {
                        Velocity(el, {opacity: 0, height: 0}, {complete: done})
                    }, delay)
                }
            }
        }
        return h('transition-group', data, ctx.children)
    }
})

E n d . End. End.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值