Vue小球抛物线效果

本文通过cube-ui的create-api,展示了如何利用Vue、CSS和JavaScript制作小球抛物线动画。动画由内外两层组成,内层水平移动,外层应用贝塞尔曲线实现抛物线轨迹。在动画结束后,小球会自动销毁。具体实现细节包括ball组件的模板、JS和CSS代码,以及组件在main.js中的全局注册。

使用cube-ui的create-api,制作小球抛物线动画,动画结束后小球自动销毁。讲述先欠着,有时间再补,先上效果:
在这里插入图片描述代码实现:
首先,ball 组件,需要两层,内层水平线性移动,外层垂直贝塞尔曲线运动,实现抛物线效果。
组件模板部分:

<template>
  <transition name="ball"
    @before-enter="beforeDrop"
    @enter="dropping"
    @after-enter="afterDrop"
  >
    <div class="ball" v-show="btnShow">
      <div class="inner"></div>
    </div>
  </transition>
</template>

js部分:

export default {
  name: 'Ball',
  data () {
    return {
      btnShow: false,
      startPos: {},
      stopPos: {}
    }
  },
  methods: {
    // 对外接口
    drop (startPos, stopPos) {
      this.btnShow = !this.btnShow
      this.startPos = startPos
      this.stopPos = stopPos
    },
    beforeDrop (el) { // 过渡开始前,将小球设置到指定起始位置
      const inner = el.getElementsByClassName('inner')[0] // 重置子元素位置,为下一次动画做准备
      inner.style.transform = 'translate3d(0, 0, 0)'

      el.style.transform = `translate3d( ${this.startPos.x}px, ${this.startPos.y}px, 0)`
    },
    dropping (el, done) { // 过渡,将小球移动到指定终点位置
      this._reflow = el.offsetWidth // 触发重绘

      const inner = el.getElementsByClassName('inner')[0]
      el.style.transform = `translate3d(0, ${this.stopPos.y}px, 0)` // 外层
      inner.style.transform = `translate3d(${this.stopPos.x}px, 0, 0)` // 内层
      done()
    },
    afterDrop (el) {
      this.btnShow = !this.btnShow // 动画结束后隐藏小球
      // 对外发送动画结束信号
      el.addEventListener('transitionend', () => {
        this.$emit('transitionOver')
      })
    }
  }
}

css部分:

.ball{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 20;
  transition: all 0.4s cubic-bezier(.32,-0.43,.89,.66);
  .inner{
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background-color: red;
    transition: all 0.4s linear;
  }
}

之后是调用部分:
模板部分:

<template>
  <div class="balls-container">
    <button @click="handleClick">click me</button>
    <div class="pos posStart" ref="posStart"></div>
    <div class="pos posStop" ref="posStop"></div>
  </div>
</template>

js部分:

const BALL_LEN = 10
function createBalls () {
  const balls = []
  for (let i = 0; i < BALL_LEN; i++) {
    balls.push({
      hasBall: false
    })
  }
  return balls
}
export default {
  name: 'DropBalls',
  data () {
    return {
      ballList: createBalls()
    }
  },
  methods: {
    handleClick () {
      const elStratRect = this.$refs.posStart.getBoundingClientRect()
      const elStopRect = this.$refs.posStop.getBoundingClientRect()
      const startPos = { // 设置ball起始位置
        x: elStratRect.left - 5,
        y: elStratRect.top - 5
      }
      const stopPos = { // 设置ball结束位置
        x: elStopRect.left - 5,
        y: elStopRect.top - 5
      }
      for (let i = 0; i < this.ballList.length; i++) {
        const ball = this.ballList[i]
        if (!ball.hasBall) {
          ball.compBall = this.$createBall() // 动态创建ball组件,并将其实例保存在ballList的元素属性中
          ball.compBall.drop(startPos, stopPos) // 调用ball组件drop方法
          ball.compBall.$on('transitionOver', () => { // 监听ball组件过渡结束事件
            ball.compBall.remove() // 动画结束后清除DOM元素
            delete ball.compBall // 删除compBall属性
            ball.hasBall = false // 失去compBall属性的ball元素,将其hasBall属性重置为false,以供下次使用
          })
          ball.hasBall = true // ball添加compBall属性,保存ball组件实例后,将hasBall属性置为true
          return // 保存本次点击事件创建的ball组件实例后,跳出循环
        }
      }
    }
  }
}

css部分:

.pos{
  position: absolute;
  width: 10px;
  height: 10px;
  background-color: red;
  border-radius: 50%;
}
.posStart{
  left: 100px;
  top:300px;
}
.posStop{
  left:250px;
  top:600px;
}

另外,ball组件需要到main.js中注册:

import { createAPI } from 'cube-ui'

import Ball from './components/ball.vue'
createAPI(Vue, Ball, ['transitionOver'])
Vue.config.productionTip = false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值