js 实现点击按钮小球加入购物车动画

本文旨在实现类似点击按钮实现小球加入购物车效果。

使用技术:

  • Vue2
  • 使用 Pubsub 监听按钮点击事件(如果不想用也可以自己改造下)
  • 监听 onmousemove 来获取按钮点击时的鼠标位置

小球组件:

html + css:

小球父元素:定义了一些基本样式。采用 fixed 布局,让小球相对浏览器窗口进行定位;通过 opacity 控制显隐。

小球:采用任意图片。

js 复制代码
<template>
  <div class="ball-wrap"
    ref="ball"
    :style="{
      opacity: ball.show,
      width: size + 'px',
      height: size + 'px',
    }"
  >
    <i class="el-icon-document" ></i>
  </div>
</template>

<style scoped>
.ball-wrap {
  border-radius: 50%;
  z-index: 9999;
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #165BD3;
}
.el-icon-document {
  color: #fff !important;
  margin: 0 !important;
}
</style>

js:

props:控制小球大小、动画持续时间(不传也有默认值)

data:通过 ball.show 来控制小球的 opacity

mounted:

小球当前位置通过变量 currentMousePos 来记录,通过使用监听函数 onmousemove 修改当前鼠标位置。

小球挂载时增加监听 onmousemove,使用 debounce 防抖函数,保证 50ms 内只更新一次鼠标位置

核心方法 drop:开启小球动画

exportRecordsListNav:小球结束处的 dom 元素,直接通过 id 获取了,用 ref 还需要跨组件获取,觉得有些麻烦

主要流程:获取结束元素的位置 -> 设置小球到初始位置 -> 设置结束位置 -> 动画结束后小球隐藏、清除 transition 属性

js 复制代码
<script>
  import debounce from 'lodash/debounce'
  // 记录小球当前位置、通过监听 onmousemove 来更新小球位置
  const currentMousePos = {
    x: 0,
    y: 0
  }
  export default {
    props: {
      // 球的大小
      size: {
        type: Number,
        default: 30
      },
      //持续时间
      duration: {
        type: Number,
        default: 1000
      },
    },
    data() {
      return {
        ball: {
          show: 0,
        },
      };
    },
    mounted() {
      // 初始化小球,控制小球显隐
      this.initBall()
      // 小球挂载时监听 onmousemove,使用 debounce 保证 50ms 内只更新一次小球位置
      window.addEventListener('mousemove', debounce((e) => {
        currentMousePos.x = e.clientX
        currentMousePos.y = e.clientY
      }, 50))
    },
    methods: {
      initBall(){
        this.ball.show = 0
      },
      // 外部调用方法,开始执行动画
      drop(){
        // 获取结束位置的元素及坐标
        const exportRecordsListNav = document.getElementById('export-records-list')
        const endPos = {}
        endPos.x = exportRecordsListNav.getBoundingClientRect().left
        endPos.y = exportRecordsListNav.getBoundingClientRect().top
      
        // 小球显示
        this.ball.show = 1
        // 设置小球初始位置
        this.$refs.ball.style.transform = `translate(${currentMousePos.x}px, ${currentMousePos.y}px)`
      
        // 延时是为了防止合并移动
        setTimeout(() => {
           // 增加动画效果
          this.$refs.ball.style.transition = `transform ${this.duration}ms ease-in-out`
          // 设置小球结束位置
          this.$refs.ball.style.transform = `translate(${endPos.x}px, ${endPos.y}px)`
          
          // 动画结束后,小球隐藏,清除动画效果
          // 清除动画效果是为了下次小球从 (0,0) 移动到初始位置时不需要有动画
          setTimeout(()=>{
            this.ball.show = 0
            this.$refs.ball.style.transition = 'unset'
          }, this.duration)
        }, 100)
      },
    }
  }
 </script>

使用方式:

我将结束元素和小球封装成了一个组件,原因是认为工作项目中小球动画只和该导航栏相关。

由于加入购物车的按钮会在很多不同的单页面 page 里,因此使用 Pubsub 技术告诉结束元素此刻点击了按钮,再由结束元素组件调用 drop 方法,这样在其他页面只需进行发布订阅,不需要关注其他操作。

结束元素组件:

js 复制代码
<template>
  <div>
    <span id="export-records-list">购物车</span>
    <MovableBall ref="movableBallRef"/>
  </div>
</template>

<script>
import MovableBall from '@/components/movable-ball/index.vue' 
import Pubsub from 'pubsub-js'
export default {
  data () {},
  components: {
    MovableBall,
  },
  mounted () {
    // 订阅消息、接受到消息后执行 moveBall 方法
    Pubsub.subscribe('add-to-card', this.moveBall)
  },
  methods: {
    moveBall() {
      if(this.$refs.movableBallRef) {
        // 开启小球动画
        this.$refs.movableBallRef.drop()
      }
    },
  },
}
</script>

点击「加入购物车按钮」的单页面:

js 复制代码
<script>
import Pubsub from 'pubsub-js'
export default {
    methods: {
        // 点击按钮加入购物车
        addToCard() {
            // 发布消息
            Pubsub.publish('add-to-card')                        
        }
    }
}
</script>

参考文档: 仿加入购物车飞入动画效果

相关推荐
王解2 分钟前
速度革命:esbuild如何改变前端构建游戏 (1)
前端·vite·esbuild
葡萄城技术团队10 分钟前
使用 前端技术 创建 QR 码生成器 API1
前端
DN金猿12 分钟前
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
前端·vue.js·pdf
鸽鸽程序猿20 分钟前
【前端】javaScript
开发语言·前端·javascript
秦时明月之君临天下28 分钟前
React和Next.js的相关内容
前端·javascript·react.js
上官花雨1 小时前
什么是axios?怎么使用axios封装Ajax?
前端·ajax·okhttp
米奇妙妙wuu1 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人1 小时前
react-amap海量点优化
前端·react.js·前端框架
闹闹没有闹1 小时前
socket连接封装
前端
qq_364371722 小时前
Vue 内置组件 keep-alive 中 LRU 缓存淘汰策略和实现
前端·vue.js·缓存