4.过渡类名实现vue动画

1. Vue.js里面的动画


  • 一个小小的动画可以很大程度上提高用户的体验

  • vue中将一个动画分成了进入和退出两个阶段,两个阶段在内部也分为开始执行跟执行完成两个关键帧

  • 这样处理我们就可以只关心关键帧的属性不用关心其实现过程

  • 下面将引入一个图片,其讲解的内容就是动画的各个阶段


    transition.png
  • 我们需要自己写每个关键帧的样式,以及其在关键帧之间的过渡方式

  • 我们可以这样理解,整个动画分为进入跟退出两个部分,分别在进入跟退出的时候执行,当进入的时候动画元素的状态是v-enter状态,直到进入动作结束的时候动画元素会变成v-enter-to状态,期间有执行过程的,这一过程就是我们的v-enter-active这一过程,通过对这三者进行控制,我们可以很轻松的实现我们的一些动画,一个退出的动画也分为两个时间点跟一个时间段

  • 这两个动画分别称为半场动画,两者一起可以构成一场动画

  • 虽然vue给我们分成了两个半场动画,四个关键帧,但是实际上在通常情况下v-enter跟v-leave-to,v-leave跟v-enter-to这些关键帧的样式是相同的,因此我们通常会将动画的关键帧分为这两类,同时给定其css样式

  • 使用过渡类名实现动画时首先我们需要使用<transition>标签将需要被启用动画的元素包起来

  • transition元素是vue官方提供的元素

  • 之后需要自定义两组样式来设置transition包裹的元素中的关键帧样式

  • 通过控制transition的name属性来定义定制动画类

  • 通过这种方式我们可以定制很多不同的动画,并在不同元素上面使用不同动画

  • 到时候只需要在样式中把前缀作为定制样式的前缀就可以了

  • 如:<transition name="my">那么在定义动画类样式的时候就可以用.my-enter,my-leave-to,my-enter-action,my-leave-action来定制自己的动画了

HTML

<div id="app">
        <input type="button" value="切换动画控制器" @click="flag=!flag">
        <transition>
            <div v-if="flag" style="color: cornflowerblue;font-size: 90px;">yerts</div>
        </transition>
        <hr>
        <input type="button" value="自定义动画类名控制器" @click="flag2=!flag2">
        <transition name="yerts">
            <div v-if="flag2" style="color:darkorange;font-size: 90px;">yerts</div>
        </transition>
    </div>
/* 元素起始关键帧 */
/* 这里我们只关心起始两个关键帧 */
.v-enter,
.v-leave-to {
    opacity: 0;
    transform: translateX(100px);
}

/* 动画的过渡效果,也就是上半场跟下半场动画的过渡效果 */
.v-enter-active,
.v-leave-active {
    /* 过渡所有属性,过渡时间为0.5秒,过渡效果为擦除 */
    transition: all 0.5s ease;
}

/* 自定义类名动画样式 */
.yerts-enter,
.yerts-leave-to {
    opacity: 0;
    transform: translateY(20px);
}

.yerts-enter-active,
.yerts-leave-active {
    transition: all 0.3s ease;
}
let data = {
    flag: true,
    flag2: true
}

let vm = new Vue({
    el: '#app',
    data: data
})

2. 使用animate css第三方动画库实现vue中的动画


  • 有些入场和出场效果我们很难自己实现
  • 这时我们就可以使用第三方库来实现我们想要的效果
  • 下面将介绍animate css这一第三方动画库
  • 在项目使用的时候我们可以使用:npm install animate.css --save来安装这一动画库
  • 之后将其引入到项目中就可以了,它是css库,因此需要使用link标签来引入
  • 之后需要什么动画效果的话只要在其官网把想要使用的动画名称记住,直接在项目中使用即可
  • 其动画元素依然要用transition来包裹,只需要改变这个标签的enter-active-class=""leave-active-class=""就可以了,这些类要把将要使用的动画效果包含进来,我们在官网找到我们要用的效果放到这些类里面即可
  • 在实现动画的时候我们需要在这些类中再加一个animated类,这个类可以将动画挂载上去,其他内容不用再设置css来控制
  • 我们也可以把这个animated类挂在我们将要实现动画的元素上面,这样就不用两边都写animated
  • 我们也可以使用:duration其时间单位是毫秒如:duration="400"就是说我们的入场动画跟出场动画分别为400毫秒属性指定动画的长度,要记住到现在为止我们都在讲的是单个元素的动画实现
<input type="button" value="自定义动画类名控制器" @click="flag2=!flag2">
        <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter:400,leave:200}">
            <div v-show="flag2" class="bool animated ">
            </div>
        </transition>

3. 钩子函数实现半场动画


  • 上面两种方式都定义了上半场和下半场两场动画,也就是整场动画都实现了,下面我们将会使用钩子函数实现半场动画
  • 因为,有些时候我们只需要上半场动画或者下半场动画
  • 半场动画就是类似于我们加入购物车的时候一个小圆球用动画的方式从上面飞到下面,这种动画的下半场就不用实现了
  • 动画的钩子函数我们也可以在Vue官网找到,并通过生命周期函数实现我们想要实现的效果
<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"
>
  <!-- ... -->
</transition>
methods: {
  // --------
  // 进入中
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // 离开时
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}
  • 这些钩子函数非常类似于组建的生命周期函数
  • 在html结构中使用就是事件的绑定机制实现的
  • 在这些生命周期函数中的第一个参数是el,类似于自定义指令里面的参数el一样,是元素的dom内容
  • 下面将给出一个例子

<input type="button" value="自定义动画类名控制器" @click="flag2=!flag2">
        <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
            <div v-show="flag2" class="bool">
            </div>
        </transition>

methods: {
        // --------
        // 进入中
        // --------
        beforeEnter: function (el) {
            // 表示动画入场之前,通过这个生命周期我们可以指定元素的起始位置和状态
            //"translate(0,0)"代表动画开始之前元素在哪儿,我们就指定位置在哪儿
            el.style.transform = "translate(0,0)"
        },
        // 当与 CSS 结合使用时
        // 回调函数 done 是可选的
        enter: function (el, done) {
            //设置过渡,不然元素会直接出现在两个位置
            //可以理解为这个属性是强制动画刷新的属性
            el.offsetWidth
            // 表示动画开始之后的状态,我们可以在这里定义动画在完成时的位置和状态
            el.style.transform = "translate(150px,450px)"
            el.style.transition = "all 2s ease"
            //其实done()这个函数就是afterEnter的引用,也就是立即调用done
            done()
        },
        afterEnter: function (el) {
            // 动画完成之后会调用这一个钩子函数
            //我们在这儿直接让小球消失就可以了
            this.flag2 = !this.flag2
            //我们发现其实在动画在完成完整个动画之后还会等一段时间,这一段事件就是我们定义的动画的长度,因此我们需要一个可以
            //在动画完成之后立即执行下面的函数的一个方法,这时我们就可以使用done()这个方法了
            //这个内容需要在enter里面执行,因为enter里面才定义了我们的动画事件
        }
    },

4. 使用transition group来实现对一系列元素的动画设置


  • 我们可以使用transition group给几个元素同时加上同一个动画
  • 用transition group包住我们要产生动画的内容就可以完成这一效果了

html

<label>
                name:
            </label>
            <input type="text" name="" id="" v-model:value="name">
            <label>
                age:
            </label>
            <input type="text" name="" id="" v-model:value="age">
            <input type="button" value="加入名单" @click="addNew">

            <transition-group>
                <div v-for="(item,index) in itemList" :key="index">
                    <div class="item">{{ item.name }}----{{item.age}}----{{index}}</div>
                </div>
            </transition-group>

JavaScript

addNew: function () {
            let tempItem = {
                name: this.name,
                age: this.age
            }
            this.itemList.push(tempItem)
            this.name = ''
            this.age = ''
        }

Css

/* 用于给每一列添加动画效果 */
.item {
    border: 1px solid black;
    margin: 20px;
    padding: 10px;
}

/* 鼠标滑过的时候每一列的动画效果 */
.item:hover {
    background-color: aquamarine;
    transition: all 1s ease;
}

/* 动画组的动画效果 */
.v-enter,
.v-leave-to {
    opacity: 0;
    transform: translateY(30px);
}

/* 动画组的动画效果 */
.v-enter-active,
.v-leave-active {
    transition: all 0.5s ease;
}
  • 我们实现了元素删除的动画发现当我们在进行删除的时候会有元素在下面等着上面的元素被删除干净才会去占其位置,这种效果对用户体验来说是非常不友好的,因此用.v-move这个类来解决上面的问题
  • 同时我们也需要给v-leave-to中的position属性设置为absolute,这样才会保证我们元素在撤离的时候就占其位置,但是这也导致了另外一个问题,那就是元素的宽度会出现塌陷的情况,这个问题我们可以在给元素设置宽度的时候将其宽度设置为100%
  • 这样就完美解决了元素删除动画的实现,这里:key绑定的值很重要,不然我们无论点哪个元素都会从最下面开始删除,key的值必须要是唯一的,后面也不会变的那种

html

<transition-group>
                    <div v-for="(item,index) in itemList" :key="item.id" class="item">
                        <div @click="del(index)">{{ item.name }}----{{item.age}}</div>
                    </div>
                </transition-group>

javascript

addNew: function () {
            let tempItem = {
                name: this.name,
                age: this.age
            }
            this.itemList.push(tempItem)
            this.name = ''
            this.age = ''
        },
        del: function (index) {
            this.itemList.splice(index, 1)
            console.log(index)
        }

css

/* 动画组的动画效果 */
.v-enter,
.v-leave-to {
    opacity: 0;
    transform: translateY(30px);
}

/* 动画组的动画效果 */
.v-enter-active,
.v-leave-active {
    transition: all 0.5s ease;
}

/* 用于解决元素被删除之后会让后面的等的问题 */
.v-move {
    transition: all 0.5s ease;

}

.v-leave-to {
    position: absolute;
}
  • 我们可以在transition group身上加上一个appear属性,这样的话可以在页面加载进来的时候就对被包含的元素都使用一个入场动画
  • transition group 的实现方式是在被动画的元素外面加上一个span标签来实现的,但是span标签里面包含一个块元素是不符合w3c的代码规范的,因此我们需要想一种办法把外面的span给他取消掉,我们可以将transition group的tag属性设置为"div"来避免这种情况的发生

html

<transition-group appear tag="div">
                    <div v-for="(item,index) in itemList" :key="item.id" class="item">
                        <div @click="del(index)">{{ item.name }}----{{item.age}}</div>
                    </div>
                </transition-group>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容