vue3:过渡和动画

前言

本来对过渡和动画这块没怎么重视,直到我发现了这个:

在这里插入图片描述
我知道我应该好好学习过渡和动画了。这个功能来自于Element的Tabs标签页组件,感兴趣的可以自己去试试。

以下内容来源于官方文档:过渡 & 动画

过渡和动画概述

基于class和style的过渡

Transform 和 Opacity

官方文档说Transform 和 Opacity不会触发重绘,因此可以用来提升性能。比如可以使用transform来代替topleft 的移动。

硬件加速

诸如 perspective、backface-visibility 和 transform:translateZ(x) 等 property 将让浏览器知道你需要硬件加速。
如果要对一个元素进行硬件加速,可以应用以下任何一个 property (并不是需要全部,任意一个就可以):

perspective: 1000px;  //这个属性允许你改变3D元素是怎样查看透视图。
backface-visibility: hidden;   //定义当元素背面向屏幕时是否可见。
transform: translateZ(0);  //平移

缓动效果

缓动效果是在动画中表达深度的一个重要方式。动画新手最常犯的一个错误是在起始动画节点使用 ease-in,在结束动画节点使用 ease-out。实际上你需要的是反过来的。

进入过渡和离开过渡

单元素过渡

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:

1、自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
2、如果过渡组件提供了 JavaScript 钩子函数 ,这些钩子函数将在恰当的时机被调用。
3、如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此处指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)

这里只介绍class方式的过渡,JavaScript钩子函数的方式几乎不适用,可以自己看官方文档。

在进入/离开的过渡中,会有 6 个 class 切换。

1、v-enter-from:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2、v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3、v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter-from 被移除),在过渡/动画完成之后移除。
4、v-leave-from:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
5、v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
6、v-leave-to:离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave-from 被移除),在过渡/动画完成之后移除。

关于class类的命名略

demo:Vue 路由切换动画

一般情况下过渡类只会用到下面的4个类,并且基本是成对出现:
enter-activeleave-active 表示过渡生效时的状态;enter-fromleave-to 表示过渡的开始状态

多个组件之间的过渡

组件之间的过渡更简单——我们甚至不需要 key 属性。取而代之的是,我们包裹了一个动态组件 :

官方demo:

<div id="demo">
  <input v-model="view" type="radio" value="v-a" id="a"><label for="a">A</label>
  <input v-model="view" type="radio" value="v-b" id="b"><label for="b">B</label>
  <transition name="component-fade" mode="out-in">
    <component :is="view"></component>
  </transition>
</div>

.component-fade-enter-active,
.component-fade-leave-active {
    
    
  transition: opacity 0.3s ease;
}

.component-fade-enter-from,
.component-fade-leave-to {
    
    
  opacity: 0;
}

在这里插入图片描述

列表过渡

我们回到文章开头的那个过渡效果,怎么同时渲染整个列表,比如使用 v-for?在这种场景下,我们会使用 <transition-group> 组件。

特点:

  • 默认情况下,它不会渲染一个包裹元素,但是你可以通过 tag attribute 指定渲染一个元素。
  • 过渡模式不可用,因为我们不再相互切换特有的元素。
  • 内部元素总是需要提供唯一的 key attribute 值。
  • CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。

列表的进入/离开过渡

应用:增删数组中的元素

<template>
    <div>
        <div>
            <el-button type="primary" size="small" @click="addNumber">添加</el-button>
            <el-button type="primary" size="small" @click="delNumber">移出</el-button>
        </div>
        <transition-group name="list-complete" class="list" tag="div">
            <div class="list-item" v-for="item in list" :key="item">
                <span>{
    
    {
    
     item }}</span>
            </div>
        </transition-group>
    </div>
</template>

<script setup lang="ts">
import {
    
     ref } from 'vue'

let list = ref([1, 2, 3, 4])

let addNumber = () => {
    
    
    list.value.push(list.value.length + 1)
}

let delNumber = () => {
    
    
    list.value.splice(list.value.length - 1, 1)
}
</script>

<style scoped lang="scss">
.list {
    
    
    display: flex;
    width: 1000px;
    height: 22px;
    margin-top: 30px;

    .list-item {
    
    
        width: 80px;
        height: 20px;
        line-height: 20px;
        text-align: center;
        border: 1px solid #ddd;
        transition: all 0.8s ease;
    }
}

.list-complete-enter-from {
    
    
    transform: translateX(-10px);
    opacity: 0;
}

.list-complete-leave-to {
    
    
    transform: translateX(-5px);
    opacity: 0;
}

.list-complete-enter-active,
.list-complete-leave-active {
    
    
    transition: opacity 0.3s ease;
}
</style>

tag="div"表示transition-group最后被渲染成div标签

效果
在这里插入图片描述

列表的交错过渡

应用:搜索过滤
通过 data attribute 与 JavaScript 通信,就可以实现列表的交错过渡,我们可以基于官方demo进行简单修改

gsap是一个高效的js动画库,既然vuedemo里都用到了这个库,那么这是非常值得学习的

<template>
    <div>
        <el-row :gutter="20">
            <el-col :span="4">
                <el-input v-model="filterText" placeholder="请输入关键字"></el-input>
            </el-col>
            <el-col :span="2">
                <el-button type="primary" @click="search">搜索</el-button>
            </el-col>
        </el-row>
        <transition-group name="staggered-fade" tag="ul" :css="false" @before-enter="beforeEnter" @enter="enter"
            @leave="leave">
            <li v-for="(item, index) in result" :key="item" :data-index="index">
                {
    
    {
    
     item }}
            </li>
        </transition-group>
    </div>
</template>

<script setup lang="ts">
import gsap from 'gsap'
import {
    
     ref } from 'vue'

let list = ref(['东方耀', '孙悟空', '猪八戒', '李白', '东方镜', '李信'])
let result = ref(['东方耀', '孙悟空', '猪八戒', '李白', '东方镜', '李信'])

let filterText = ref('')

let search = () => {
    
    
    result.value = list.value.filter(e => e.includes(filterText.value))
}

let beforeEnter = (el) => {
    
    
    el.style.opacity = 0
    el.style.height = 0
}
let enter = (el, done) => {
    
    
    gsap.to(el, {
    
    
        opacity: 1,
        height: '1.6em',
        delay: el.dataset.index * 0.15,
        onComplete: done
    })
}
let leave = (el, done) => {
    
    
    gsap.to(el, {
    
    
        opacity: 0,
        height: 0,
        delay: el.dataset.index * 0.15,
        onComplete: done
    })
}

</script>

<style scoped lang="scss">
.list {
    
    
    margin-top: 30px;

    .list-item {
    
    
        height: 40px;
        line-height: 40px;
    }
}
</style>

效果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41897680/article/details/125092057