当前位置:网站首页 > Vue.js开发 > 正文

vue中动画效果的实现

一,过渡动画的实现

1,无过渡,直接变化

<template> <div class="testBox"> <div class="testCon" :style="{ width: width + 'px' }"></div> <div class="testBtn" @click="clickBtn">点击按钮</div> </div> </template> <script setup> import { 
    ref } from 'vue'; const width = ref(10); const clickBtn = () => (width.value += 100); </script> <style lang="scss" scoped> .testBox { 
    overflow: hidden; height: 100vh; padding: 100px 50px; box-sizing: border-box; .testCon { 
    height: 200px; background: pink; } .testBtn { 
    margin-top: 10px; height: 60px; line-height: 60px; border: 1px solid #35aeff; background: #35aeff; border-radius: 10px; } } </style> 

为了好讲述,只看一次点击。也就是开始时width:10px,结束时width:110px。在没有设置过渡的时候,变化是突兀的,生硬的。如下图:
在这里插入图片描述

2,设置过渡,设置时间和速率

过渡的实现。可以理解为:记录起始状态,然后添加一个从开始到结束的时间和速度。
主要就是利用css3的transition来设置。需要监听谁的属性变化,就写在谁的样式中

 .testCon { 
    height: 200px; background: pink; transition: width 2s linear;//监听这个元素的width属性的变化, } 

于是就会监听这个width属性,从开始到结束的变化,会被拉长到2s来线性变化。
在这里插入图片描述
当想要监听该元素所有元素的变动的时候,只要把属性改成all即可:

<template> <div class="testBox"> <div :class="['testCon', btnClick ? 'btnClick' : '']"></div> <div class="testBtn" @click="clickBtn">点击按钮</div> </div> </template> <script setup> import { 
    ref } from 'vue'; const btnClick = ref(false); const clickBtn = () => { 
    btnClick.value = true; }; </script> <style lang="scss" scoped> .testBox { 
    overflow: hidden; height: 100vh; padding: 100px 50px; box-sizing: border-box; .testCon { 
    width: 100px; height: 100px; background: pink; } .btnClick { 
    height: 200px; width: 200px; background: red; transition: all 2s linear; } .testBtn { 
    margin-top: 10px; height: 60px; line-height: 60px; border: 1px solid #35aeff; background: #35aeff; border-radius: 10px; } } </style> 

主要是从这个样式:

.testCon { 
    width: 100px; height: 100px; background: pink; } 

变成:

 .btnClick { 
    height: 200px; width: 200px; background: red; transition: all 2s linear; } 

这样一来,就会给该元素所有变动的属性增加过渡变化的效果:
在这里插入图片描述
也就是说,过渡主要是transition这个css样式产生的效果,

transition :transition-property(执行变换的属性) || transition-duration(执行变换的时间) || transition-timing-function(执行变换的速率) || transition-delay(延迟变换的时间); 

transition-property(执行变换的属性)

transition-property 可取的值
none 没有属性会获得过渡效果
all 所有属性都将获得过渡效果,也是其默认值
property CSS 属性名称列表,逗号隔开

transition-duration(执行变换的时间

过渡的持续时间,取值time为数值,单位为s(秒)或者ms(毫秒),其默认值是0,也就是变换时是即时的。

transition-timing-function(执行变换的速率)

描述
linear 相同速度开始至结束
ease 慢速开始,然后变快,然后慢速结束
ease-in 慢速开始
ease-out 慢速结束
ease-in-out 慢速开始和结束
cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。

transition-delay(延迟变换的时间)

二,animation 和 keyframe 的组合实现动画

过渡动画,只能定义首尾两个状态。而animation可以自定义多个帧的状态之间的过渡效果。从而实现真正的动画。

1,animation的取值

描述
animation-name 规定需要绑定到选择器的 keyframe 名称
animation-duration 规定完成动画所花费的时间,以秒或毫秒计
animation-timing-function 规定动画的速度曲线
animation-delay 规定在动画开始之前的延迟,默认值为0
animation-iteration-count 规定动画应该播放的次数,默认值为1
animation-direction 规定是否应该轮流反向播放动画,默认值是正向

2,keyframe

@keyframes 就是让程序员设置一定序列的动画帧,然后提供给animation使用的。
使用方法:
当使用百分比用法时:

@keyframes 动画名字{ 
    0% { 
    top: 0; left: 0px} 50% { 
    top: 30px; left: 20px; } 100% { 
    top: 0; left: 30px;} } 

使用的方法如下:

<template> <div class="testBox"> <div class="testCon"></div> </div> </template> <script setup></script> <style lang="scss" scoped> .testBox { 
    overflow: hidden; height: 100vh; padding: 100px 50px; box-sizing: border-box; .testCon { 
    animation: testAni 3s ease-in-out infinite; } } @keyframes testAni { 
    0% { 
    width: 50px; height: 50px; background: #cd4a48; border-radius: 50px; } 50% { 
    width: 100px; height: 100px; background: #e72365; border-radius: 0; } 100% { 
    width: 50px; height: 50px; background: #04aef1; border-radius: 50px; } } </style> 

实现的效果:
在这里插入图片描述
当使用from-to用法时:

@keyframes preloader { 
    from { 
    transform: rotate(0deg);//其实这里写的就是支持过渡动画的属性啦 } to { 
    transform: rotate(360deg); } } 

不同于transition,使用animation自动触发,无需事件触发。

三,transform变换

在制作动画的时候,常常要使用到属性变化。transform就是变形,主要包括旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix。

transform: none || transform-functions 

none:表示不进么变换;transform-function表示一个或多个变换函数,用空格分开。
transform-function变换函数有以下几种:

1,旋转rotate

通过指定的角度参数对原元素指定一个2D rotation(2D 旋转),需先有transform-origin属性的定义(默认dom元素的中心)。transform-origin定义的是旋转的基点,其中angle是指旋转角度,如果设置的值为正数表示顺时针旋转,如果设置的值为负数,表示逆时针旋转。 如:transform:rotate(30deg):

<template> <div class="testBox"> <div class="testCon"></div> </div> </template> <script setup></script> <style lang="scss" scoped> .testBox { 
    overflow: hidden; height: 100vh; padding: 100px 50px; box-sizing: border-box; .testCon { 
    width: 100px; height: 100px; animation: testAni 3s ease-in-out infinite; } } @keyframes testAni { 
    0% { 
    background: #04aef1; border-radius: 50px; } 50% { 
    background: #e72365; border-radius: 0; transform: rotate(180deg); } 100% { 
    background: #04aef1; border-radius: 50px; } } </style> 

在这里插入图片描述

2,移动translate

移动translate我们分为三种情况:translate(x,y)水平方向和垂直方向同时移动(也就是X轴和Y轴同时移动);translateX(x)仅水平方向移动(X轴移动);translateY(Y)仅垂直方向移动(Y轴移动),如果是负值,则是反方向移动,当然,也可以用transform-origin来控制基准。

@keyframes testAni { 
    0% { 
    background: #04aef1; border-radius: 50px; } 50% { 
    background: #e72365; border-radius: 0; transform: rotate(180deg); transform: translate(50px, 50px); } 100% { 
    background: #04aef1; border-radius: 50px; } } 

实现的便是这样的效果:
在这里插入图片描述

3,scale缩放

scale(x,y)使元素水平方向和垂直方向同时缩放(也就是X轴和Y轴同时缩放);scaleX(x)元素仅水平方向缩放(X轴缩放);scaleY(y)元素仅垂直方向缩放(Y轴缩放),但它们具有相同的缩放中心点和基数,其中心点就是元素的中心位置,缩放基数为1,如果其值大于1元素就放大,反之其值小于1,元素缩小。同样的,它可以用transform-origin来控制基准。

 50% { 
    background: #e72365; border-radius: 0; transform: scale(1.5, 2); } 

在这里插入图片描述

4,扭曲skew

扭曲skew和translate、scale一样同样具有三种情况:skew(x,y)使元素在水平和垂直方向同时扭曲(X轴和Y轴同时按一定的角度值进行扭曲变形);skewX(x)仅使元素在水平方向扭曲变形(X轴扭曲变形);skewY(y)仅使元素在垂直方向扭曲变形(Y轴扭曲变形)。

 50% { 
    background: #e72365; border-radius: 0; transform: skewX(30deg); } 

在这里插入图片描述
单个的动画看起来有些死板,但是多种结合在一起,就会有神效:

<div id="preloader"> <span></span> <span></span> <span></span> <span></span> </div> #preloader { 
    position: relative; width: 42px; height: 42px; animation: preloader 5s infinite linear; } #preloader span { 
    width: 20px; height: 20px; position: absolute; background: red; // display: block; animation: preloader_6_span 1s infinite linear; } #preloader span:nth-child(1) { 
    background: #2ecc71; } #preloader span:nth-child(2) { 
    left: 22px; background: #9b59b6; animation-delay: 0.2s; //延迟0.2s后开始动画 } #preloader span:nth-child(3) { 
    top: 22px; background: #3498db; animation-delay: 0.4s; //延迟0.4s后开始动画 } #preloader span:nth-child(4) { 
    top: 22px; left: 22px; background: #f1c40f; animation-delay: 0.6s; //延迟0.6s后开始动画 } @keyframes preloader { 
    from { 
    transform: rotate(0deg); } to { 
    transform: rotate(360deg); } } @keyframes preloader_6_span { 
    0% { 
    transform: scale(1); } 50% { 
    transform: scale(0.5); } 100% { 
    transform: scale(1); } } 

在这里插入图片描述

四,vue中的动画效果

1,普通的过渡动画

Vue 3 中提供了一些动画的封装,使用内置的 transition 组件来控制组件的动画。
在这里插入图片描述
按照官网的说法,就是被transition包裹的组件,会有这六种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 的名字,Vue 的官网有一个图给出了很好的解释,图里的 v-enter-from 中的 v,就是我们设置的 name 属性。
实际上,这个过程就是过渡动画的体现。当元素进入的那一帧,会添加v-enter-from的class,设置了初始状态。而v-enter-to则是元素开始进入到完成会添加的class,用来设置元素过渡的结束状态。v-enter-active则是整个过渡时间内会存在的class。
也就是上面那张图实际上是这样的:
在这里插入图片描述
于是,v-enter-active和v-leave-active就可以被用来定义进入过渡的过程时间,延迟和曲线函数。因为这两个类在过渡的时间内一直存在,过渡完成后才删除。
而v-enter-from和v-leave-to则可以用来设置动画的开始和结束。
另外两个可以不使用,而用元素自身的class替代:

<template> <div id="demo"> <button @click="data.noActivated = !data.noActivated">Toggle</button> <transition name="fade"> <p v-if="data.noActivated" class="test">hello</p> </transition> </div> </template> <script setup> import { 
    reactive } from "vue"; const data = reactive({ 
    noActivated: false }); </script> <style lang="scss" scoped> .test { 
    color: green; opacity: 1; } .fade-enter-active, .fade-leave-active { 
    transition: all 5s ease; } .fade-enter-from, .fade-leave-to { 
    color: black; opacity: 0; } </style> 

实现的效果:

在这里插入图片描述
也就是在元素渲染的那段动画中:

1,fade-enter-from设置了初始状态 2,fade-enter-active设置了过渡的动画和时间 3,元素本身的class:test充当设置了最终状态。 
1,元素本身的class:test充当设置了初始状态。 2,fade-leave-active设置了过渡的动画和时间 3,fade-leave-to设置了最终状态。 

2,列表的进入/离开过渡动画

transition 元素作为单个元素/组件的过渡效果。transition 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。它的这六个class就是放在这个子元素上的。所以列表渲染就不用这个,而是使用transition-grou来包裹,至于六种class则是添加在item上。用法和上文说的一样,我习惯用元素本身的class,来取代v-enter-to和v-leave-from。所以没设置这两个。

<template> <div id="demo"> <button @click="clickBtn">增加按钮</button> <transition-group name="fade" tag="ul"> <li v-for="(item, index) in data.testList" :key="index" class="test"> { 
   { 
    item.content }} </li> </transition-group> </div> </template> <script setup> import { 
    reactive } from "vue"; const data = reactive({ 
    testList: [ { 
    content: "第一个" } ] }); function clickBtn() { 
    data.testList.push({ 
    content: "下一个" }); } </script> <style lang="scss" scoped> .test { 
    color: red; font-size: 18px; } .fade-enter-active, .fade-leave-active { 
    transition: all 2s ease; } .fade-enter-from, .fade-leave-to { 
    color: black; opacity: 0; transform: translateX(30px); } </style> 

在这里插入图片描述

3,js动画配合transition

<template> <div class="title"> <input type="text" @keypress.enter="add" v-model="title" /> <button @click="clear">清理</button> </div> <div class="content"> <transition-group name="flip-list" tag="ul"> <li v-for="(item, index) in todoList" :key="item.content"> <input type="checkbox" v-model="item.done" /> <span :class="[item.done ? 'inactive' : 'active']"> { 
   { 
    item.content }} </span> <span class="remove-btn" @click="removeTodo($event, index)"></span> </li> </transition-group> </div> <span class="dustbin">🗑</span> <div class="animate-wrap"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" > <div class="animate" v-show="animate.show">📋</div> </transition> </div> </template> <script setup> import { 
    ref, reactive } from "vue"; //把这个useTodo解耦出来 function useTodos() { 
    let title = ref(""); let todoList = ref([ { 
    content: "五湖四海皆一望", done: false }, { 
    content: "千江有水千江月", done: true } ]); function add() { 
    const obj = { 
    content: title.value, done: false }; todoList.value.push(obj); title.value = ""; } function clear() { 
    todoList.value = todoList.value.filter((v) => !v.done); } return { 
    title, todoList, add, clear }; } //其实你可以把组件内部的任何一段代码,从组件文件里抽离出一个独立的文件进行维护。 //再在这个组件中使用,于是这些东西就不依赖于this上下文了,这里再解构赋值出来 let { 
    title, todoList, add, clear } = useTodos(); const { 
    animate, beforeEnter, enter, afterEnter, removeTodo } = useAnimation(); function useAnimation() { 
    let animate = reactive({ 
    show: false, el: null }); const dustbin = { 
    el: null, pos: [], init(queryStr) { 
    this.el = document.querySelector(queryStr); this.getPos(); }, getPos() { 
    const { 
    left, top } = this.el.getBoundingClientRect(); this.pos[0] = left; this.pos[1] = top; } }; function beforeEnter(el) { 
    let dom = animate.el; let rect = dom.getBoundingClientRect(); const aniEl = document.querySelector(".animate"); //动画元素 调整到dustbin的位置,也可以css直接写精准位置 aniEl.style.left = `${ 
     dustbin.pos[0]}px`; aniEl.style.top = `${ 
     dustbin.pos[1]}px`; //计算并赋值偏移量 let dx = dustbin.pos[0] - rect.left; let dy = dustbin.pos[1] - rect.top; el.style.transform = `translate(-${ 
     dx}px, ${ 
     dy * -1}px)`; } function enter(el, done) { 
    document.body.offsetHeight; el.style.transform = `translate(0,0)`; el.addEventListener("transitionend", done); } function afterEnter(el) { 
    animate.show = false; el.style.display = "none"; } function removeTodo(e, i) { 
    animate.el = e.target; animate.show = true; todoList.value.splice(i, 1); dustbin.init(".dustbin"); } return { 
    animate, beforeEnter, enter, afterEnter, removeTodo }; } </script> <style lang="scss" scoped> .active { 
    color: v-bind(color); } .flip-list-move { 
    transition: transform 0.8s ease; } .flip-list-enter-active, .flip-list-leave-active { 
    transition: all 1s ease; } .flip-list-enter-from, .flip-list-leave-to { 
    opacity: 0; transform: translateX(30px); } .dustbin { 
    position: absolute; top: 0; right: 0; } .animate-wrap .animate { 
    position: fixed; right: 10px; top: 10px; z-index: 100; transition: all 0.5s linear; } </style> 

实现的效果:
在这里插入图片描述

到此这篇vue中动画效果的实现的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • js中的同步与异步的理解2024-12-01 21:45:07
  • webpack5学习与实战-(六)-babel-loader解析js文件2024-12-01 21:45:07
  • vue2使用脚手架配置prettier报错:‘prettier/prettier‘: context.getPhysicalFilename is not a function2024-12-01 21:45:07
  • inquirer:命令行中与用户进行交互的js库2024-12-01 21:45:07
  • vue2项目中全局引入scss变量2024-12-01 21:45:07
  • vue3开启eslint之后报错:error Parsing error: ‘>‘ expected2024-12-01 21:45:07
  • 模块化使用vuex2024-12-01 21:45:07
  • vue3的语法使用总结api2024-12-01 21:45:07
  • vue项目history路由的配置2024-12-01 21:45:07
  • copyWebpackPlugin的使用及常见问题(glob及Path ............... is not in cwd)2024-12-01 21:45:07
  • 全屏图片