VueJS使用create-keyframe-animation与动画钩子完成复杂动画

2019-04-0922:09:46WEB前端开发Comments2,228 views字数 5108阅读模式

Vue中使用create-keyframe-animation与动画钩子完成复杂动画,分享给大家文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

VueJS使用create-keyframe-animation与动画钩子完成复杂动画文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

如何实现这个动画?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

 效果分析文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

点`start`的时候,我们把整个动画拆分为两种效果(过渡和动画)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

1. 中间cd消失,下方播放条显示,这是属于`过渡`文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

2. `过渡`开始的同时,cd同时移动、放大、缩小到左下方播放条 ,这属于`动画`文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

上面的效果是【过渡】加【动画】同时使用完成的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

  • 对于第一种【过渡】,我们用vue中transition标签,加设置v-enter、v-leave-to、v-enter-active、v-leave-enter即可完成
  • 对于第二种【动画】,我们就要用keyframe来完成了。

这里我们先完成第一种过渡文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

vue中模板节点文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

<template>
 <div class="index">
 <transition>
  <div class="cd-box" ref="cdWrapper" v-show="fullScreen">
 // CD图片 (动画的时候图片初始位置)
  <img src="../assets/" class="bg">
  </div>
 </transition>
 <button @click="switchMode" style="position:absolute;top:0;left:10px;">start</button>
 <transition>
 // 下面播放状态框
  <div class="mini-player-box" v-show="!fullScreen">
 // 状态看里面的图片 (动画的时候图片结束位置)
  <div class="mini-img">
   <img src="../assets/" >
  </div>
  </div>
 </transition>
 </div>
</template>

结构很简单,基本就是 两个大div ,然后把div的布局按效果图那些布置。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

css部分(省略布局部分)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

.cd-box
 &.v-enter-active, &.v-leave-active
  transition: all 0.4s
 &.v-enter, &.v-leave-to
  opacity: 0
.mini-player-box
 &.v-enter-active, &.v-leave-active
  transition: all 0.4s 
 &.v-enter, &.v-leave-to
  transform: translate3d(0, 40px, 0)
  opacity: 0

这样在fullScreen变量改变的时候,就会触发【过渡】文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

这里我们完成第二种动画文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

首先安装插件npm i create-keyframe-animation 这个插件是用js写css的keyframe动画用的,至于为什么keyframe不在css里面写呢?那是因为屏幕大小不一样,会导致需要移动的px不一样,所以要动态计算。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

给 <transition> 添加动画钩子文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

<transition 
  @enter="enter"
  @after-enter="afterEnter"
  @leave="leave"
  @after-leave="afterLeave"
 > 
  <div class="cd-box" ref="cdWrapper" v-show="fullScreen">
  <img src="../assets/" class="bg">
  </div>
 </transition>

计算偏移量(中心点到中心的偏移,图中红线距离)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

VueJS使用create-keyframe-animation与动画钩子完成复杂动画文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

// 获得偏移量,以及scale
_getPosAndScale() {
 // 左下角图片的宽度
  const targetWidth = 40
 // cd宽度
  const width = 300
  const scale = targetWidth / width
  // 这里的 x,y要算,过程省略,无非就是加加减减,这的x,y都是算出来了的
  const x = -167.5
  const y = 497
  return {x ,y , scale}
 },

x,y的数值代表什么?见图文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

VueJS使用create-keyframe-animation与动画钩子完成复杂动画文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

这里x为什么是负的,y是正的呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

因为 浏览器的坐标系的中心点是在左上角 的,如图文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

VueJS使用create-keyframe-animation与动画钩子完成复杂动画文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

那么动画从 cd中心到左下角,X偏移为负,y偏移为正文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

然后用animations插件执行动画钩子文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

 // enter是指当 cd从隐藏到显示的动画,
 enter(el, done) {
  const {x, y, scale} = ()

  let animation = {
  // 第0帧的时候,先让图片缩小,显示在右下角
  0: {
   transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`
  },
  // 60%的时候,让图片回到cd中心,变大
  60: {
   transform: `translate3d(0 ,0 , 0) scale()`
  },
  // 变回原来的尺寸,会有一个回弹的效果
  100: {
   transform: `translate3d(0 ,0 , 0) scale(1)`
  }
  }
  // 动画的一些配置
  ({
  name: 'move',
  animation,
  presets: {
   duration: 400,
   easing: 'linear'
  }
  })
//运行动画
 (this.$, 'move', done)
 },
 afterEnter(){
 //运行完动画之后,注销掉动画
  ('move')
  this.$.style.animation = ''
 },
 // leave是指 cd从显示到隐藏的动画
 leave(el, done) {
  this.$.style.transition = 'all 0.4s'
  const {x, y, scale} = ()
  // 这里我们只要直接移动变小就可以了
  this.$.style['transform'] = `translate3d(${x}px,${y}px,0) scale(${scale})`
   
 // 监听transitionend 事件在 CSS 完成过渡后触发done回调  
 this.$.addEventListener('transitionend', () => {
  done()
  })
 },
 afterLeave() {
  this.$.style.transition = ''
  this.$.style['transform'] = ''
 }

写到这里,我们就把刚开始的效果给写完啦!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

但在写js的keyframe的时候文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

我们还可以加上rotate,让动画效果有一个回弹效果文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

let animation = {
  0: {
   transform: `translate3d(${x}px, ${y}px, 0) scale(${scale}) rotate(0deg)`
  },
  60: {
   transform: `translate3d(0 ,0 , 0) scale() rotate(365deg)`
  },
  100: {
   transform: `translate3d(0 ,0 , 0) scale(1) rotate(360deg)`
  }
  }

所有源码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html

<template>
 <div class="index">
 <transition 
  @enter="enter"
  @after-enter="afterEnter"
  @leave="leave"
  @after-leave="afterLeave"
 > 
  <div class="cd-box" ref="cdWrapper" v-show="fullScreen">
  <img src="../assets/" class="bg">
  </div>
 </transition>
 <button @click="switchMode" style="position:absolute;top:0;left:10px;">start</button>
 <transition>
  <div class="mini-box" v-show="!fullScreen">
  <div class="mini-img">
   <img src="../assets/" >
  </div>
  </div>
 </transition>
 </div>
</template>

<script>
/* eslint-disable */
import animations from 'create-keyframe-animation'
export default {
 components: {},
 props: {},
 data() {
 return {
  fullScreen: true
 }
 },
 computed: {},
 watch: {},
 created() {},
 mounted() {
 // const {x, y, scale} = ()
 (())
 (animations)
 },
 methods: {
 switchMode() {
   = !
 },
 _getPosAndScale() {
  const targetWidth = 40
  const paddingLeft = 20
  const paddingBottom = 20
  const paddingTop = 0
  const width = 300
  const scale = targetWidth / width
  const x = -(window.innerWidth / 2 - paddingLeft)
  const y = window.innerHeight - paddingTop - paddingBottom - width / 2
  return {x ,y , scale}
 },
 enter(el, done) {
  const {x, y, scale} = ()

  let animation = {
  0: {
   transform: `translate3d(${x}px, ${y}px, 0) scale(${scale}) rotate(0deg)`
  },
  60: {
   transform: `translate3d(0 ,0 , 0) scale() rotate(365deg)`
  },
  100: {
   transform: `translate3d(0 ,0 , 0) scale(1) rotate(360deg)`
  }
  }
  ({
  name: 'move',
  animation,
  presets: {
   duration: 400,
   easing: 'linear'
  }
  })
  (this.$, 'move', done)
 },
 afterEnter(){
  ('move')
  this.$.style.animation = ''
 },
 leave(el, done) {
  this.$.style.transition = 'all 0.4s'
  const {x, y, scale} = ()
  this.$.style['transform'] = `translate3d(${x}px,${y}px,0) scale(${scale})`
  // this.$.style['transform'] = 'rotate(360deg)'
  // transitionend 事件在 CSS 完成过渡后触发
  this.$.addEventListener('transitionend', () => {
  done()
  })
 },
 afterLeave() {
  this.$.style.transition = ''
  this.$.style['transform'] = ''
 }
 }
}
</script>
<style lang="stylus" scoped>
.index
 background: #eee
 width: 100%
 height: 100%
 display : flex
 flex-direction: column
 justify-content : space-between
 align-items: center
 .cd-box
 display : flex
 justify-content : center
 align-items : center
 width: 300px
 height: 300px
 background: #eee
 border-radius: 50%
 &.v-enter-active, &.v-leave-active
  transition: all 0.4s
 &.v-enter, &.v-leave-to
  opacity: 0
 .bg
  width: 300px
  height: 300px
  border-radius: 50%
 .mini-box
 position: absolute
 bottom: 0
 right: 0
 left: 0
 display : flex 
 align-items center 
 border: 1px solid #555
 width: 100%
 height: 40px
 box-sizing : border-box
 &.v-enter-active, &.v-leave-active
  transition: all 0.4s 
 &.v-enter, &.v-leave-to
  transform: translate3d(0, 40px, 0)
  opacity: 0
 .mini-img
  height: 40px
  width: 40px
  box-sizing : border-box
  img
  height: 100%
  width: 100%
</style>
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/11305.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/11305.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定