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>
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容