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


Posted in Javascript onApril 09, 2019

本篇文章主要介绍了 Vue中使用create-keyframe-animation与动画钩子完成复杂动画,分享给大家

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

如何实现这个动画?

 效果分析

点`start`的时候,我们把整个动画拆分为两种效果(过渡和动画)。

1. 中间cd消失,下方播放条显示,这是属于`过渡`

2. `过渡`开始的同时,cd同时移动、放大、缩小到左下方播放条 ,这属于`动画`

上面的效果是【过渡】加【动画】同时使用完成的

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

这里我们先完成第一种过渡

vue中模板节点

<template>
 <div class="index">
 <transition>
  <div class="cd-box" ref="cdWrapper" v-show="fullScreen">
 // CD图片 (动画的时候图片初始位置)
  <img src="../assets/bj.png" alt="" 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/bj.png" alt="" >
  </div>
  </div>
 </transition>
 </div>
</template>

结构很简单,基本就是 两个大div ,然后把div的布局按效果图那些布置。

css部分(省略布局部分)

.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变量改变的时候,就会触发【过渡】

这里我们完成第二种动画

首先安装插件npm i create-keyframe-animation 这个插件是用js写css的keyframe动画用的,至于为什么keyframe不在css里面写呢?那是因为屏幕大小不一样,会导致需要移动的px不一样,所以要动态计算。

给 <transition> 添加动画钩子

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

计算偏移量(中心点到中心的偏移,图中红线距离)

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

// 获得偏移量,以及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的数值代表什么?见图

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

这里x为什么是负的,y是正的呢?

因为 浏览器的坐标系的中心点是在左上角 的,如图

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

那么动画从 cd中心到左下角,X偏移为负,y偏移为正

然后用animations插件执行动画钩子

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

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

写到这里,我们就把刚开始的效果给写完啦!

但在写js的keyframe的时候

我们还可以加上rotate,让动画效果有一个回弹效果

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

所有源码

<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/bj.png" alt="" 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/bj.png" alt="" >
  </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} = this._getPosAndScale()
 console.log(this._getPosAndScale())
 console.log(animations)
 },
 methods: {
 switchMode() {
  this.fullScreen = !this.fullScreen
 },
 _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} = this._getPosAndScale()

  let animation = {
  0: {
   transform: `translate3d(${x}px, ${y}px, 0) scale(${scale}) rotate(0deg)`
  },
  60: {
   transform: `translate3d(0 ,0 , 0) scale(1.1) rotate(365deg)`
  },
  100: {
   transform: `translate3d(0 ,0 , 0) scale(1) rotate(360deg)`
  }
  }
  animations.registerAnimation({
  name: 'move',
  animation,
  presets: {
   duration: 400,
   easing: 'linear'
  }
  })
  animations.runAnimation(this.$refs.cdWrapper, 'move', done)
 },
 afterEnter(){
  animations.unregisterAnimation('move')
  this.$refs.cdWrapper.style.animation = ''
 },
 leave(el, done) {
  this.$refs.cdWrapper.style.transition = 'all 0.4s'
  const {x, y, scale} = this._getPosAndScale()
  this.$refs.cdWrapper.style['transform'] = `translate3d(${x}px,${y}px,0) scale(${scale})`
  // this.$refs.cdWrapper.style['transform'] = 'rotate(360deg)'
  // transitionend 事件在 CSS 完成过渡后触发
  this.$refs.cdWrapper.addEventListener('transitionend', () => {
  done()
  })
 },
 afterLeave() {
  this.$refs.cdWrapper.style.transition = ''
  this.$refs.cdWrapper.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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 刷新页面的代码小结 推荐
Apr 02 Javascript
JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版
Apr 02 Javascript
javascript 事件绑定问题
Jan 01 Javascript
javascript操作数组详解
Dec 17 Javascript
javascript弹性运动效果简单实现方法
Jan 08 Javascript
简单谈谈axios中的get,post方法
Jun 25 Javascript
JavaScript实现图片切换效果
Aug 12 Javascript
jQuery的时间datetime控件在AngularJs中的使用实例(分享)
Aug 17 jQuery
jQuery动态添加li标签并添加属性和绑定事件方法
Feb 24 jQuery
vue实现鼠标移入移出事件代码实例
Mar 27 Javascript
原生js实现的观察者和订阅者模式简单示例
Apr 18 Javascript
使用vant的地域控件追加全部选项
Nov 03 Javascript
基于three.js实现的3D粒子动效实例代码
Apr 09 #Javascript
Koa 中的错误处理解析
Apr 09 #Javascript
简单说说如何使用vue-router插件的方法
Apr 08 #Javascript
利用Bootstrap Multiselect实现下拉框多选功能
Apr 08 #Javascript
纯javascript实现选择框的全选与反选功能
Apr 08 #Javascript
详解小程序如何避免多次点击,重复触发事件
Apr 08 #Javascript
「中高级前端面试」JavaScript手写代码无敌秘籍(推荐)
Apr 08 #Javascript
You might like
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
js利用Array.splice实现Array的insert/remove
2009/01/13 Javascript
模拟select的代码
2011/10/19 Javascript
jQuery对象的selector属性用法实例
2014/12/27 Javascript
深入理解JavaScript系列(39):设计模式之适配器模式详解
2015/03/04 Javascript
js实现漂浮回顶部按钮实例
2015/05/06 Javascript
JS实现很实用的对联广告代码(可自适应高度)
2015/09/18 Javascript
超精准的javascript验证身份证号的具体实现方法
2015/11/18 Javascript
jquery ajax双击div可直接修改div中的内容
2016/03/04 Javascript
基于javascript实现图片切换效果
2016/04/17 Javascript
bootstrapValidator自定验证方法写法
2016/12/01 Javascript
JavaScript数据结构之二叉查找树的定义与表示方法
2017/04/12 Javascript
React学习笔记之事件处理(二)
2017/07/02 Javascript
node 使用 async 控制并发的方法
2018/05/07 Javascript
vue better scroll 无法滚动的解决方法
2018/06/07 Javascript
layui实现点击按钮给table添加一行
2018/08/10 Javascript
JavaScript对象原型链原理解析
2020/01/22 Javascript
webpack+vue-cil 中proxyTable配置接口地址代理操作
2020/07/18 Javascript
python实现linux下使用xcopy的方法
2015/06/28 Python
使用python加密自己的密码
2015/08/04 Python
打包发布Python模块的方法详解
2016/09/18 Python
Python3 伪装浏览器的方法示例
2017/11/23 Python
通过实例简单了解Python sys.argv[]使用方法
2020/08/04 Python
Numpy ndarray 多维数组对象的使用
2021/02/10 Python
python 统计list中各个元素出现的次数的几种方法
2021/02/20 Python
String是最基本的数据类型吗?
2013/06/13 面试题
有个性的自我评价范文
2013/11/15 职场文书
销售副总经理岗位职责
2013/12/11 职场文书
火车来了教学反思
2014/02/11 职场文书
个人租房协议书
2014/04/09 职场文书
初中班主任评语大全
2014/04/24 职场文书
团日活动总结书
2014/05/08 职场文书
邀请函格式范文
2015/02/02 职场文书
认真学习保证书
2015/02/26 职场文书
JS监听Esc 键触发事键
2021/04/14 Javascript
小程序wx.getUserProfile接口的具体使用
2021/06/02 Javascript