js动画和vue动画实践

239 阅读6分钟

写在前面

在实际开发中,为了增加用户体验,经常会使用到过渡动画,而过渡动画在CSS中是通过transitionanimation实现的。而在Vue中,Vue本身中内置了一些组件和API可以帮助我们方便的实现过渡动画效果。

备注: 所谓过渡动画,简而言之就是从一种状态变成另一种状态的过程;所以不管是vue动画还是js动画都是需要触发条件的,触发条件就是在哪种情况下会触发一种状态到另外一种状态的变化;比如(v-if、v-show、:hover、:active、或者click点击等等~)

一、vue过渡

vue中提供transition组件为元素自动添加进入/离开的过渡效果

在线demo编写: stackblitz.com/edit/vitejs…

1. transition组件j基本使用

<template>
  <div class="box">
    <button class="btn" @click="btnClick">click</button>
    <transition>
      <img
        v-if="isShow"
        src="./assets/vue.svg"
        class="logo vue"
        alt="Vue logo"
      />
    </transition>
  </div>
</template>
<script setup>
import { ref } from 'vue';

const isShow = ref(false);

const btnClick = () => {
  isShow.value = !isShow.value;
};
</script>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
}
.btn {
  margin-bottom: 50px;
}
.logo {
  width: 100px;
  height: 100px;
}

/* 进入之前和离开后的样式 */
.v-enter-from,
.v-leave-to {
  opacity: 0;
}
/* 离开和进入过程中的样式 */
.v-enter-active,
.v-leave-active {
  /* 添加过渡动画 */
  transition: opacity 8s ease;
}
/* 进入之后和离开之前的样式 */
.v-enter-to,
.v-leave-from {
  opacity: 1;
}

</style>

2. transition组件的class命名规则

transition组件的class命名规则默认前缀是v-, 如果给transition设置了name属性,比如设置name="test",则class命名的规则的前缀就变成test-。 (v-enter-from变成test-enter-from

<template>
  <div class="box">
    <button class="btn" @click="btnClick">click</button>
    <transition name="test">
      <img
        v-if="isShow"
        src="./assets/vue.svg"
        class="logo vue"
        alt="Vue logo"
      />
    </transition>
  </div>
  <!-- <HelloWorld msg="Vite + Vue" /> -->
</template>
<script setup>
import { ref } from 'vue';

const isShow = ref(false);

const btnClick = () => {
  isShow.value = !isShow.value;
};
</script>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
}
.btn {
  margin-bottom: 50px;
}
.logo {
  width: 100px;
  height: 100px;
}

/* 进入之前和离开后的样式 */
.test-enter-from,
.test-leave-to {
  opacity: 0;
}
/* 离开和进入过程中的样式 */
.test-enter-active,
.test-leave-active {
  /* 添加过渡动画 */
  transition: opacity 8s ease;
}
/* 进入之后和离开之前的样式 */
.test-enter-to,
.test-leave-from {
  opacity: 1;
}
</style>

1.3 过渡的阶段

image.png

image.png

二、js过渡和动画

1. transition过渡

1.1 transition语法

transition: 过渡属性 过渡时间  过渡动画函数  过渡延迟

// 需要多个属性过渡时用逗号隔开
transition: 过渡属性1 过渡时间1  过渡动画函数1  过渡延迟1, 过渡属性2 过渡时间2  过渡动画函数2  过渡延迟2

// 需要所有属性都过渡, 则过渡属性是all
transition: all 过渡时间  过渡动画函数  过渡延迟

过渡动画函数:transition的状态变化速度(又称timing function),默认不是匀速的,而是逐渐放慢,这叫做ease。 `

除了ease以外,其他模式还包括

(1)linear:匀速

(2)ease-in:加速

(3)ease-out:减速

(4)cubic-bezier函数:自定义速度模式

最后那个cubic-bezier,可以使用工具网站来定制。


img{
    transition: 1s height cubic-bezier(.83,.97,.05,1.44);
}

上面的代码会产生一个最后阶段放大过度、然后回缩的效果。

1.2 transition实战

可以在菜鸟平台上练习:www.runoob.com/try/try.php…

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title>
<style> 
div
{
    width:100px;
    height:100px;
    background:red;
    transition:width 4s;
    // transition:width 4s ease, transform 4s;  指定多个过渡属性时逗号隔开
}

div:hover
{
    width:300px;
    transform: translateY(-4px);
}
</style>
</head>
<body>

<div></div>

<p>鼠标移动到 div 元素上,查看过渡效果。</p>

</body>
</html>

鼠标放到div上之后,相当于触发了hover,此时宽度会从100px慢慢经过4s的过程,慢慢增长到300px,同时div还会在y轴上面上移4px;当鼠标从div上脱离之后,会自动从hover状态慢慢经过4s过渡到原始状态(也就是宽度从300px慢慢递减到100px,transform同理)

1.3 transition注意点

注意点:

(1)目前,各大浏览器(包括IE 10)都已经支持无前缀的transition,所以transition已经可以很安全地不加浏览器前缀。

(2)不是所有的CSS属性都支持transition,完整的列表查看这里,以及具体的效果

(3)transition需要明确知道,开始状态和结束状态的具体数值,才能计算出中间状态。比如,height从0px变化到100px,transition可以算出中间状态。但是,transition没法算出0px到auto的中间状态,也就是说,如果开始或结束的设置是height: auto,那么就不会产生动画效果。类似的情况还有,display: none到block,background: url(foo.jpg)到url(bar.jpg)等等。


局限性:

transition的优点在于简单易用,但是它有几个很大的局限。

(1)transition需要事件触发,所以没法在网页加载时自动发生。

(2)transition是一次性的,不能重复发生,除非一再触发。

(3)transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。

(4)一条transition规则,只能定义一个属性的变化,不能涉及多个属性。

CSS Animation就是为了解决这些问题而提出的。

2. 动画

完整demo:www.runoob.com/try/try.php…

动画和过渡有什么区别呢?个人感觉是过渡定义的是从开始状态到结束状态变化的过程;而动画是除了定义开始状态到结束状态变化的过程,并且可以将这个过程拆分成不同的阶段,可以定义每个阶段是什么状态,比如从开始状态变化到50%的时候,可以定义50%那刻的状态。

2.1 基本使用

首先,CSS Animation需要指定动画一个周期持续的时间,以及动画效果的名称


div:hover {
  animation: 1s rainbow;
}

上面代码表示,当鼠标悬停在div元素上时,会产生名为rainbow的动画效果,持续时间为1秒。为此,我们还需要用keyframes关键字,定义rainbow效果


@keyframes rainbow {
  0% { background: blue; }
  50% { background: black; }
  100% { background: yellowgreen; }
}

上面代码表示,rainbow效果一共有三个状态,分别为起始(0%)、中点(50%)和结束(100%)。如果有需要,完全可以插入更多状态。效果如下(完整代码如下,可自行尝试: www.runoob.com/try/try.php… )。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title>
<style> 
div
{
	width:100px;
	height:100px;
	background:red;
}

div:hover
{
	animation: 1s rainbow forwards;
}

@keyframes rainbow {
  0% { background: blue; }
  50% { background: black; }
  100% { background: yellowgreen; }
}
</style>
</head>
<body>

<div></div>


</body>
</html>

默认情况下,动画只播放一次。加入infinite关键字,可以让动画无限次播放。

div:hover {
  animation: 1s rainbow infinite;
}

也可以指定动画具体播放的次数,比如3次。

div:hover {
  animation: 1s rainbow 3;
}

2.2 keyframes的写法


@keyframes rainbow {
  0% { background: #c00 }
  50% { background: orange }
  100% { background: yellowgreen }
}

0%可以用from代表,100%可以用to代表,因此上面的代码等同于下面的形式

@keyframes rainbow {
  from { background: #c00 }
  50% { background: orange }
  to { background: yellowgreen }
}

甚至,可以把多个状态写在一行。

@keyframes pound {
  fromto { transform: none; }
  50% { transform: scale(1.2); }
}

2.3 相关的属性

2.3.1 animation-fill-mode

动画结束以后,会立即从结束状态跳回到起始状态。如果想让动画保持在结束状态,需要使用animation-fill-mode属性

(1)none:默认值,回到动画没开始时的状态。

(2)backwards:让动画回到第一帧的状态。

(3)forwards: 表示让动画停留在结束状态。

(4)both: 根据animation-direction(见后)轮流应用forwards和backwards规则。

div:hover {
  animation: 1s rainbow forwards;
}

2.3.2 animation-direction

动画循环播放时,每次都是从结束状态跳回到起始状态,再开始播放。animation-direction属性,可以改变这种行为。

取值:normal(默认值)、alternate、reverse、alternate-reverse等值

下面看这个例子:

@keyframes rainbow {
  0% { background-color: yellow; }
  100% { background: blue; }
}

image.png

2.4 简写

简写语法如下:


animation: animation-duration animation-delay animation-name animation-timing-function animation-iteration-count animation-fill-mode animation-direction

简写实践如下:


div:hover {
  animation: 1s 1s rainbow linear 3 forwards normal;
}


div:hover {
  animation-name: rainbow;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-delay: 1s;
    animation-fill-mode:forwards;
  animation-direction: normal;
  animation-iteration-count: 3;
}


参考系列

www.ruanyifeng.com/blog/2014/0…