展开收起动画(JavaScript 钩子)

前面使用了vue的css类名实现基础的动画效果,这里要做一个更酷炫的效果。 如上图,从迷你播放器进入全屏的时候,迷你播放器中的图片飞入全屏的唱片中(逐渐放大飞入),或则说更大,然后再缩小到正常状态,和顶部的贝塞尔曲线效果相呼应

先来看一下示意图,到底是怎么个飞?原理如下图

1. 飞入原理

简单一句话:在全屏播放器打开的时候,让cd元素先移动到mini播放器的小cd处,也就是 大圆中心点,移动到小圆中心点

移动的时候是 基于大圆为基准,所以这里是 x轴 往左移动(负数),y轴往下移动(正数)

那么就要计算出往左移动多少,和往下移动多少。

x轴偏移量 = -(屏幕的宽度/2 - 小圆的半径 - 小圆距离屏幕左边的距离) y轴的偏移量 = 屏幕的高度 - cd距离顶部高度 - 小圆中心点距离屏幕底部的距离 - 大圆的半径

上面的高度半径什么的,都是以容器的css样式计算的,其他的高度宽度都是 css 写死的,padding值,图片容器宽高等,只有大圆的半径是屏幕宽度的百分之80

所以就计算出来了 x,y轴的偏移量。再加上缩放的比例(小圆占大圆的比例)

在效果上看起来就是从迷你播放器cd上慢慢变大并且飞入到大cd中

2. 飞入动画代码

这里使用一个js创建动画css代码的库 create-keyframe-animation vue的动画钩子

    <transition name="normal"
                @enter="enter"
                @after-enter="afterEnter"
                @leave="leave"
                @after-leave="afterLeave"
    >
    methods: {
      enter (el, done) {
        // 进入的时候,让小cd飞入大cd位置,过程了先慢慢放大最后再缩小成大cd效果
        const {x, y, scale} = this._getPosAndScale()
        let animation = {
          0: {
            // 动画开始,让大cd缩小成小cd一致,且把自己移动到小cd位置处
            transform: `translate3d(${x}px,${y}px,0) scale(${scale})`
          },
          60: {
            // 移动回大cd原来的位置,且cd放大一点点
            transform: `translate3d(0,0,0) scale(1.1)`
          },
          100: {
            // 最后大cd还原成原来的大小
            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 () {
        this.$refs.cdWrapper.style.animation = ''
      },
      leave (el, done) {
        // 离开的收,让大cd缩小移动到小cd处
        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.addEventListener('transitionend', done)
      },
      afterLeave () {
        this.$refs.cdWrapper.style.transition = ''
        this.$refs.cdWrapper.style[transform] = ''
      },
      // 获取大cd圆心点移动和缩放到小cd圆心点的位置和缩小比例
      _getPosAndScale () {
        let miniLeftPadding = 40 / 2 + 20  // 迷你播放器的图形40px,paddingLeft=20,小图片中心点距离左边就是40
        let miniBottomPadding = 60 / 2  // mini-player 元素高60,图片是居中的,所以中心点距离底部30
        let normalTopPadding = 80 // middle 元素距离顶部80
        let normalWidth = window.innerWidth * 0.8 // cd-wrapper 的宽是容器的百分之80,容器是圆形(正方形)所以宽高一致
        let miniWidth = 40 // 迷你播放器图形宽度(因为是圆形所以宽高一致)
        let scale = miniWidth / normalWidth  // 小图形占比大图形的比例

        let x = -(window.innerWidth / 2 - miniLeftPadding)
        let y = window.innerHeight - normalTopPadding - miniBottomPadding - normalWidth / 2
        return {
          x, y, scale
        }
      }
    }
© All Rights Reserved            updated 2017-12-28 02:49:41

results matching ""

    No results matching ""