vue动画入门之小球飞入购物车

小球飞入购物车,是购物类 APP 常见的效果,飞入的动画效果可以有多种方式来实现。

1、技术方案

css 有两种方法可以实现同样的效果:

1、利用 animation 动画
2、利用 transform 和 transition

javascript 中也有运动函数的概念

https://blog.csdn.net/zhai_865327/article/details/89249138

张鑫旭大神有一篇博客,讲的也是 js 抛物线运动,写的非常详细:

JavaScript与元素间的抛物线轨迹运动

vue 中,则提供了用于过渡的组件:transition

一般说来,在 vue 中我更倾向于结合 css 来实现动画效果。

2、直线运动

transformtransition ,只能控制一个物体做直线运动。

  <style>
    #ball{
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background: red;
      transition: all 1s linear;
    }
  </style>
  <body>
    <div id="ball">
    </div>
  </body>
  <script>
     setTimeout(function(){
      ball.style.transform= "translate(800px, 500px)";
     },1000)
  </script>

在这里插入图片描述

假如想要实现一条类似抛物线的路径,我们得先来说一下贝塞尔曲线了。

3、贝塞尔曲线

点我理解

当然了,直接从数学来理解贝塞尔曲线,有点大材小用。这是一个 CSS3 贝塞尔曲线工具、Css3 贝塞尔曲线模板网站,可以调试曲线

http://web.chacuo.net/css3beziertool/

我们只需要知道贝塞尔曲线在代码里是如何使用的,以及如何调试就可以了。

在 jquery 动画中设置的 timing-function,如 easy、easy-in、easy-in-out 等,其实就是写好的贝塞尔曲线(cubic-bezier)。

当然,贝塞尔曲线是用来控制动画速度的,简单来说,就是变化是匀速的,还是先快后慢,先慢后快,而并非是小球所走过的路径,实际上,即便使用了贝塞尔,一个小球的飞行轨迹依然是一条直线。

这是因为,物体的运动永远受到 x 轴和 y 轴的作用,而两个轴的运动模型受到同一个 transition 的控制,二者总会合并成一个固定的方向。

就好像中学物理中力的合成。

在这里插入图片描述

大家可以在这里贝塞尔曲线看到相关的效果,我就不再赘述。

根据上面的说法,想让物体曲线运动,我们可以创建两个物体,一个负责 x轴上的动画,一个负责 y轴的动画,并且,动画的时长要一致,而 timing-function 不同步,这样两个物体的运动互相影响,就会形成曲线运动轨迹。

3、代码

<template>
  <div class="home">
    <div class="cart">cart</div>
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter"
    >
      <div class="ball" v-show="ball.show">
        <div class="innerBall">
          <i class="iconfont icon-xingxing"></i>
        </div>
      </div>
    </transition>
    <div class="menu" @click="addToCart($event)">menu</div>
  </div>
</template>

<script>
export default {
  name: 'home',
  data() {
    return {
      ball: {
        el: null,
        show: false,
      },
    }
  },
  methods: {
    beforeEnter(el) {
      let ele = this.ball.el //要添加购物车的商品
      let ract = ele.getBoundingClientRect() //商品的位置
      let elRight = this._getStyle(el, 'right') //购物车 right
      let elTop = this._getStyle(el, 'top') //购物车 top
      let x = window.innerWidth - ract.left - parseFloat(elRight) // 计算小球移动的X轴的距离
      let y = ract.top - parseFloat(elTop)// 计算小球移动的y轴的距离

      el.style.display = ''
      el.style.transform = `translateY(${y}px)` //重置小球的x轴位置

      let innerBall = el.querySelector('.innerBall')
      innerBall.style.transform = `translateX(-${x}px)`//重置小球的y轴位置
    },
    enter(el, done) {
      this._offset = document.body.offsetHeight //激发重绘

      el.style.transform = `translate(0, 0)` //小球沿着y轴移动到购物车

      let innerBall = el.querySelector('.innerBall')
      innerBall.style.transform = `translate(0, 0)`//小球沿着x轴移动到购物车

      el.addEventListener('transitionend', done)
    },
    afterEnter(el) {
      this.ball.show = false
      el.style.display = 'none'
    },
    addToCart(event) {
      this.ball.el = event.target
      this.ball.show = true
    },
    _getStyle(el, attr) {
      return el.currentStyle
        ? el.currentStyle[attr]
        : getComputedStyle(el, false)[attr]
    },
  },
}
</script>
<style lang="scss">
@import url(//at.alicdn.com/t/font_1147377_647it8vs1n.css);
.cart,
.ball {
  position: fixed;
  right: 700px;
  top: 100px;
}
.cart {
  border: 1px solid blue;
  padding: 5px 12px;
}
.ball {
  width: 10px;
  height: 10px;
  transition: all 1s cubic-bezier(0.49, -0.29, 1, 1);
}
.innerBall {
  width: 10px;
  height: 10px;
  transition: all 1s linear;
}
.menu {
  position: absolute;
  top: 500px;
  left: 50px;
  border: 1px solid blue;
  padding: 5px 12px;
  cursor: pointer;
}
</style>

来看看效果吧:
在这里插入图片描述

posted @ 2020-10-30 12:47  一亩地  阅读(464)  评论(0编辑  收藏  举报