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 相关文章推荐
javascript中的location用法简单介绍
Mar 07 Javascript
java和javascript获取word文档的书签位置对比
Jun 19 Javascript
node.js中的buffer.fill方法使用说明
Dec 14 Javascript
jQuery 获取多选框的值及多选框中文的函数
May 16 Javascript
js 数据存储和DOM编程
Feb 09 Javascript
ajax接收后台数据在html页面显示
Feb 19 Javascript
Linux CentOS系统下安装node.js与express的方法
Apr 01 Javascript
vue.js中Vue-router 2.0基础实践教程
May 08 Javascript
vue过渡和animate.css结合使用详解
Jun 14 Javascript
layui实现动态和静态分页
Apr 28 Javascript
利用vue-i18n实现多语言切换效果的方法
Jun 19 Javascript
Vue 用Vant实现时间选择器的示例代码
Oct 25 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
php _autoload自动加载类与机制分析
2012/02/10 PHP
discuz目录文件资料汇总
2014/12/30 PHP
php实现复制移动文件的方法
2015/07/29 PHP
Linux下从零开始安装配置Nginx服务器+PHP开发环境
2015/12/21 PHP
jQuery getJSON()+.ashx 实现分页(改进版)
2013/03/28 Javascript
jQuery中:animated选择器用法实例
2014/12/29 Javascript
Jquery插件之Fancybox丰富的弹出层效果附源码下载
2015/12/02 Javascript
JQuery EasyUI学习教程之datagrid 添加、修改、删除操作
2016/07/09 Javascript
js实现上传图片预览方法
2016/10/25 Javascript
jQuery图片拖动组件Dropzone用法示例
2017/01/17 Javascript
JavaScript箭头(arrow)函数详解
2017/06/04 Javascript
Bootstrap导航菜单点击后无法自动添加active的处理方法
2018/08/10 Javascript
解决layui前端框架 form表单,table表等内置控件不显示的问题
2018/08/19 Javascript
js 实现在2d平面上画8的方法
2018/10/10 Javascript
JavaScript设计模式之装饰者模式实例详解
2019/01/17 Javascript
vue elementUI使用tabs与导航栏联动
2019/06/21 Javascript
JS删除数组指定值常用方法详解
2020/06/04 Javascript
[01:38]完美世界DOTA2联赛PWL S3 集锦第四期
2020/12/21 DOTA
python读取oracle函数返回值
2016/07/18 Python
Python中import机制详解
2017/11/14 Python
python修改list中所有元素类型的三种方法
2018/04/09 Python
mac 安装python网络请求包requests方法
2018/06/13 Python
django中间键重定向实例方法
2019/11/10 Python
python 安装教程之Pycharm安装及配置字体主题,换行,自动更新
2020/03/13 Python
如何利用python正则表达式匹配版本信息
2020/12/09 Python
新电JAVA笔试题目
2014/08/31 面试题
高中生毕业自我鉴定范文
2013/12/22 职场文书
临床护士自荐信
2014/01/31 职场文书
文明餐桌活动方案
2014/02/11 职场文书
幼儿园教师师德师风演讲稿:我自豪我是一名幼师
2014/09/10 职场文书
2014年学生资助工作总结
2014/12/18 职场文书
2015年艾滋病防治工作总结
2015/05/22 职场文书
环保证明
2015/06/23 职场文书
生产设备维护保养制度
2015/08/06 职场文书
2016年“世界气象日”广播稿
2015/12/17 职场文书
Spring Bean的实例化之属性注入源码剖析过程
2021/06/13 Java/Android