vue 之 Transition && 各种动画实现,一文让你会动画

在开发中,如果没有动画的话,整个页面内容的显示和隐藏会非常的生硬!不好看,为了给予一定的用户体验,进入今天的主题

React框架本身并没有提供任何动画相关的API,所以如果需要使用的话可以使用一个第三方库react-transition-group
Vue中为我们提供了一些内置的组件和对应的API来完成动画 
一、Transition组件
1.Transition组件的原理
当插入或删除包含在transition组件中的元素时,vue将会做以下处理

就是 : 会自动把类加入到 transition组件下的根元素中,transition里面只能放单个标签( 组件 )

添加或者删除的class,常用的是如下六个 

进入 :


离开 : 

 

 


2. Use the transition
code in the Transition component
<template>
  <div class="box">
    <button @click="isShow = !isShow">switch</button>
    <!-- Wrap it with transition and name it run. The prefix of the class name is run-->
    <transition name="run">
      <!-- The display and hiding of internal elements or components will trigger the transition effect-->
      <div v-if="isShow">
        <span> 123123123123</span>
      </div>
    </transition>
  </div>
</template>
 
<script>
export default {   data() {     return {       isShow:true     };   } }; </script> <style lang="scss" scoped> // The state where the element starts to enter | The state where the element leaves the end.run-enter-from,







 



.run-leave-to {   opacity: 0; } // The state where the element enters the end | The state where the element begins to leave. It’s okay not to write here! ! ! ! ! ! .run-enter-to, .run-leave-from {   opacity: 1; } // When the element enters | end, the transition effect .run-enter-active, .run-leave-active {   // Use of transition animation   transition: opacity 2s linear 0s; } </style> effect 















illustrate


3. Use the animation
code in the Transition component
<style lang="scss" scoped>
/**
* If it is an animation effect, more than one state changes
* Just set the dynamic jike
* */
.run-enter-active {   animation: run -scale 1s linear 0s; } // set to the opposite when leaving.run -leave-active {   animation: run-scale 1s linear 0s reverse; } @keyframes run-scale {   0% {     transform: scale(0);   }   50% {     transform: scale(1.3);   }   100% {     transform: scale(1);   } } </style> Effect



















4. The type attribute of the Transition component
occurs in: when we use transition and animation at the same time

Code
<style lang="scss" scoped>
// The state where the element starts to enter | The state where the element leaves the end
.run-enter-from,
.run-leave-to {   opacity: 0; } // The state where the element enters the end| The state where the element starts to leave.run -enter-to, .run-leave-from {   opacity: 1; } // When the element enters | end, the transition effect.run -enter-active, .run-leave-active {   / / The use of transition animation   transition: opacity 2s linear 0s; } .run-enter-active {   animation: run-scale 2s linear 0s; } // set to the opposite when leaving . run-leave-active {   animation: run- scale 2s linear 0s reverse; } @keyframes run-scale {   0% {






















    transform: scale(0);
  }
  50% {
    transform: scale(1.3);
  }
  100% {
    transform: scale(1);
  }
}
</style>
效果


tip: In order to know the completion of the transition, Vue is monitoring transitionend and animationend internally

If only one of them is used, Vue can automatically identify the type and set the listener

But problems can arise if used at the same time:

It is possible that the execution of a certain animation ends, and the other animation has not ended (the time setting is different)
solution

Set the type attribute to transition and animation to clearly specify the type of Vue listening, which time shall prevail
<template>
  <div class="box">
    <button @click="isShow = !isShow">switch</button>
    < !-- here specifies which time to use as the standard -->
    <transition name="run" type="transition || animation">
      <div v-if="isShow">
        <span>123123123123</span>
      </div >
    </transition>
  </div>
</template>
Digression: In fact, the same time is generally set, and, why do you need to set the transition when there is animation? It is a magical attribute~

5、Transition组件的duration属性( 用的比较少 )
基本设置 : 同时设置进入和离开的时间
<transition name="run" :duration="1000">
  <div v-if="isShow">
    <span>123123123123</span>
  </div>
</transition>
一旦这么使用了,css中设置的 transitionend和animationend的时间就无效了,以duration时间为准

对象设置 : 分别设置进入和离开的时间
<transition name="run" :duration="{ enter: 800, leave: 1000 }">
  <div v-if="isShow">
    <span>123123123123</span>
  </div>
</transition>
6、 Transition组件的mode属性
如果transition组件中包裹的是两个元素( 组件 ),相互显示,就会发生很丑的事情

代码
<template>
  <div class="box">
    <button @click="isShow = !isShow">切换</button>
    <transition name="run">
      <div v-if="isShow">
        <span>one</span>
      </div>
      <div v-else>
        <span>two</span>
      </div>
    </transition>
  </div>
</template>
 
<script>
export default {   data() {     return {       isShow: true     };   } }; </script> <style lang="scss" scoped> .run-enter-active { // set to the opposite when leaving}   animation: run-scale 2s linear 0s;







 





.run-leave-active {
  animation: run-scale 2s linear 0s reverse;
}
@keyframes run-scale {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.3);
  }
  100% {
    transform: scale(1);
  }
}
</style>

Effect 


Cause and Solution
Reason: Because by default, the entering and leaving animations happen at the same time

Solution: Set the mode attribute

<transition name="run" mode="in-out || out-in">
  <div v-if="isShow">
    <span>one</span>
  </div>
  <div v-else>
    <span>two</span>
  </div>
</transition>
mode : in-out

mode : out-in

7、 Transition组件的appear属性
如果想要一刷新页面就展示动画,需加上

<transition name="run" mode="out-in" appear>
  <div v-if="isShow">
    <span>one</span>
  </div>
  <div v-else>
    <span>two</span>
  </div>
</transition>
8、 Transition组件的回调函数
<transition
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"
  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
  :css="false"
>
  <div v-if="isShow">
    <span>one</span>
  </div>
</transition>
:css="false". will make Vue skip css detection, improve performance, and prevent the impact of css styles during the transition process

before-enter: trigger before the animation enters ---- from, initialization operation
enter: trigger when the animation is entering ---- active, write js, execute specific animation
after-enter: trigger after the animation enters ---- to, End, finishing work
enter-cancelled: Triggered when the animation fails to enter
before-leave: Triggered before the animation leaves leave
: Triggered when the animation is leaving
after-leave: Triggered after the animation leaves
leave-cancelled: Triggered when the animation fails to leave


el : the element that performs the animation

done : When using javaScript to perform transition animations, a done callback is required, otherwise they will be called synchronously and the transition will be completed immediately 

  Next, use other packaged third-party animation libraries~

2. Use animate.css third-party animation library
Animate.css | A cross-browser library of CSS animations.

1. Install
npm install animate.css
2. Import
Import in main.js

import 'animate.css'
3. Use 01-use code
in css

<template>
  <div class="box">
    <button @click="isShow = !isShow">切换</button>
    <transition name="run" appear>
      <div v-if="isShow">
        <span>one</span>
      </div>
    </transition>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      isShow: true
    };
  }
};
</script>
 
<style lang="scss" scoped>
.run-enter-active {
  animation: lightSpeedInRight 2s linear 0s;
}
.run-leave-active {
  animation: lightSpeedOutRight 2s linear 0s;
}
</style>
Effect 

illustrate 

02- Use the class name
here you need to use enter-active-class and leave-active-class, the css part can not be written

the code

You don’t need to write the name, if you write the class name, the priority of the class name will be higher

<template>
  <div class="box">
    <button @click="isShow = !isShow">切换</button>
    <transition enter-active-class="animate__animated animate__backInDown" leave-active-class="animate__animated animate__backOutLeft">
      <div v-if="isShow">
        <span>one</span>
      </div>
    </transition>
  </div>
</template>
效果 

illustrate 

3. Using the gsap library (JS library)
 GreenSock - Docs - Gsap

In some cases, if you want to achieve animation effects through JavaScript, you can use the gsap library to complete

GSAP : The GreenSock Animation Platform ( GreenSock动画平台 ) 的缩写
可以通过JavaScript为CSS属性、SVG、Canvas等设置动画,并且兼容浏览器


1.安装
npm install gsap   
2.导入
 在组件内部导入即可

import gsap from 'gsap'
3.使用
需要使用enter和leave回调函数

<template>
  <div class="box">
    <button @click="isShow = !isShow">切换</button>
    <transition appear @enter="enter" @leave="leave" :css="false">
      <div v-if="isShow">
        <span>one</span>
      </div>
    </transition>
  </div>
</template>
<script>
// 导入
import gsap from 'gsap'
export default {
  data() {
    return {
      isShow: true
    }
  },
  methods: {
    enter(el, done) {
      // 从哪里来
      gsap.from(el, {
        // 缩小为0
        scale: 0,
        // 透明度
        opacity: 0,
        // duration duration
        : 1,
        // translatex is 200 cheaper
        x: 200,
        // this setting is better
        onComplete: done
      })
    },
    /**
     * Here you only need to formulate the initial state, no need to formulate later state, a little hard to understand
     */
    leave(el, done) {       // where to go       gsap.to(el, {         scale: 0,         opacity: 0,         duration: 1,         x: -200,         onComplete: done       })     }   } } </script> <style lang="scss" scoped></style> 4. Effect 














5.gsap额外补充 ( 数字变化效果 )
代码
<template>
  <div class="box">
    <input type="number" step="100" v-model="count" />
    <div>
      <span class="text-color">{ { showNumber.toFixed(0) }}</span>
    </div>
  </div>
</template>
<script>
import gsap from 'gsap'
export default {
  data() {
    return {
      count: 0,
      showNumber: 0
    }
  },
  watch: {
    // 监听输入值的改变
    count(newValue) {
      // 把当前this存进去,实时更改showNumber的值
      gsap.to(this, { duration: 0.5, showNumber: newValue })
    }
  }
}
</script>
<style lang="scss" scoped>
.box {
  padding: 200px;
  background-color: skyblue;
  box-shadow: 0 0 100px 0 skyblue;
  input {
    border: 3px solid rgb(7, 172, 237);
    border-radius: 10px;
    padding: 5px 10px;
    width: 100px;
    background-color: skyblue;
  }
  .text-color {
    display: inline-block;
    background-image: linear-gradient(to right, orange, purple);
    background-clip: text;
    color: transparent;
    font-size: 50px;
  }
}
</style>
效果


四、列表的过渡 transition-group
在上面的文章中,过渡动画只是针对单个元素或者单个组件的,如果希望渲染的是一个列表,并且该列表中添加、删除数据也希望有动画执行

使用 transition-group : 

1. List number increase delete effect
01-Code 
<template>
  <div class="box">
    <div>
      <button @click="addNum">add</button>
      <button @click="removeNum">delete</ button>
    </div>
    <transition-group tag="p" name="run">
      <span class="item" v-for="item in dataList" :key="item">{ { item }}< /span>
    </transition-group>
  </div>
</template>
<script>
export default {   data() {     return {       dataList: [1, 2, 3, 4, 5, 6, 7, 8, 9] ,       defaultNumber:10     }   },   methods: {     // Add a number to a random position     addNum() {









      this.dataList.splice(this.randomIndex(), 0, this.defaultNumber++)
    },
    // 随机位置删除一个数字
    removeNum() {
      this.dataList.splice(this.randomIndex(), 1)
    },
    // 随机取一个位置
    randomIndex() {
      return Math.floor(Math.random() * this.dataList.length)
    }
  }
}
</script>
<style lang="scss" scoped>
.item {
  display: inline-block;
  margin-right: 10px;
  display: inline-block;
  background-image: linear-gradient(to right, orange, purple);
  background-clip: text;
  color: transparent;
  font-size: 30px;
}
.run-enter-from,
.run-leave-to {
  opacity: 0;
  transform: translateY(50px);
}
.run-enter-active,
.run-leave-active {
  transition: all 1s linear 0s;
}
</style>
效果 

02. Effect optimization 
Optimization points: Newly added and deleted nodes have animations, but there is no animation for other nodes that need to be moved

The animation can be done through the newly added v-move class, which will be applied during the process of changing the position of the element

css code

<style lang="scss" scoped>
.item {
  display: inline-block;
  margin-right: 10px;
  display: inline-block;
  background-image: linear-gradient(to right, orange, purple);
  background-clip: text;
  color: transparent;
  font-size: 30px;
}
.run-enter-from,
.run-leave-to {
  opacity: 0;
  transform: translateY(50px);
}
.run-enter-active,
.run-leave-active {
  transition: all 1s linear 0s;
}
// 移除的时候需要加上
.run-leave-active {
  position: absolute;
}
// 加上这个
.run-move {
  transition: transform 1s linear 0s;
}
</style>
effect

03. Add shuffling effect
one-install lodash library 

npm install lodash
two --import

import _ from 'lodash'
three - use

<template>
  <div class="box">
    <div>
      <button @click="addNum">添加</button>
      <button @click="removeNum">删除</button>
      <button @click="shuffleNum">洗牌</button>
    </div>
    <transition-group tag="p" name="run">
      <span class="item" v-for="item in dataList" :key="item">{ { item }}</span>
    </transition-group>
  </div>
</template>
<script>
import _ from 'lodash'
export default {
  data() {
    return {
      dataList: [1, 2, 3, 4, 5, 6, 7, 8, 9],
      defaultNumber: 10
    }
  },
  methods: {
    // Add a number at a random position
    addNum() {       this.dataList.splice(this.randomIndex(), 0, this.defaultNumber++)     },     // Delete a number at a random position     removeNum() {       this.dataList.splice(this. randomIndex(), 1)     },     // Shuffle     shuffleNum() {       this.dataList = _.shuffle(this.dataList)     },     // Take a random position     randomIndex() {       return Math.floor(Math.random() * this.dataList.length)     }   } } </script> <style lang="scss" scoped> .item {   display: inline-block;   margin-right: 10px;   display: inline-block;






















  background-image: linear-gradient(to right, orange, purple);
  background-clip: text;
  color: transparent;
  font-size: 30px;
}
.run-enter-from,
.run-leave-to {   opacity: 0 ;   transform: translateY(50px); } .run-enter-active, .run-leave-active {   transition: all 1s linear 0s; } // need to add .run-leave-active {   position: absolute ; } // Add this property.run -move {   transition: transform 1s linear 0s; } </style> fore-effect  
















2. Alternate animation effect of the list
01-implemented with css
code

<template>
  <div class="box">
    <input type="text" v-model="keyWords" />
    <transition-group tag="ul" name="run" class="nav">
      <li class="item" v-for="item in filterData" :key="item">{ { item }}</li>
    </transition-group>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      keyWords: '',
      dataList: ['abc', 'bac', 'aec', 'qqw', 'qbf', 'aaa', 'afa']
    }
  },
  computed: {
    // 赛选一下
    filterData() {
      return this.dataList.filter((item) => item.includes(this.keyWords))
    }
  }
}
</script>
 
<style lang="scss" scoped>
.run-enter-from,
.run-leave-to {
  opacity: 0;
  transform: translateX(100px) rotate(180deg);
}
.run-enter-active,
.run-leave-active {
  transition: all 1s linear 0s;
}
.box {
  padding: 100px 0;
  background-color: skyblue;
  box-shadow: 0 0 100px 0 skyblue;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  input {
    border: 3px solid rgb(7, 172, 237);
    border-radius: 10px;
    padding: 5px 10px;
    width: 100px;
    background-color: skyblue;
  }
  .text-color {
    display: inline-block;
    background-image: linear-gradient(to right, orange, purple);
    background-clip: text;
    color: transparent;
    font-size: 50px;
  }
}
.nav {
  width: 100%;
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
  .item {
    flex: 1;
  }
}
</style>

Effect 

ps: Then it disappears and appears at the same time, and the alternating effect cannot be achieved

02-Use js to achieve animation
Through the delay attribute, achieve alternating effects

the code

<template>
  <div class="box">
    <input type="text" v-model="keyWords" />
    <transition-group tag="ul" name="run" class="nav" @enter=" enter" @leave="leave" appear>
      <!-- Use attributes like data-* to add index to each animation element -->
      <li class="item" v-for="(item, index) in filterData" :data-index="index" :key="item">
        { { item }}
      </li>
    </transition-group>
  </div>
</template>
 
<script>
import gsap from 'gsap'
export default {   data() {     return {       keyWords: ' ',       dataList: ['abc', 'bac', 'aec', 'qqw', 'qbf', 'aaa', 'afa'], // Extract animation       parameters





      transitionOption: {
        opacity: 0,
        scale: 0.5,
        height: 0,
        rotate: 360
      }
    }
  },
  computed: {
    // 赛选一下
    filterData() {
      return this.dataList.filter((item) => item.includes(this.keyWords))
    }
  },
  methods: {
    enter(el, done) {
      gsap.from(el, {
        ...this.transitionOption,
        // 设置延迟时间,因为是交替,所以每个都要不一样
        delay: el.dataset.index * 0.2,
        xPercent: -20,
        onComplete: done
      })
    },
    leave(el, done) {
      gsap.to(el, {
        ...this.transitionOption, // 设置延迟时间,因为是交替,所以每个都要不一样
        delay: el.dataset.index * 0.2,
        xPercent: 20,
        onComplete: done
      })
    }
  }
}
</script>
 
<style lang="scss" scoped>
.box {
  padding: 100px 0;
  background-color: skyblue;
  box-shadow: 0 0 100px 0 skyblue;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  input {
    border: 3px solid rgb(7, 172, 237);
    border-radius: 10px;
    padding: 5px 10px;
    width: 100px;
    background-color: skyblue;
  }
  .text-color {
    display: inline-block;
    background-image: linear-gradient(to right, orange, purple);
    background-clip: text;
    color: transparent;
    font-size: 50px;
  }
}
.nav {
  width: 100%;
  // display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
  position: relative;
  .item {
    flex: 1;
  }
}
</style>
效果 

おすすめ

転載: blog.csdn.net/qq_40999917/article/details/129780587