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>

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

相关推荐
RobinDevNotes1 小时前
从 Electron 到 GPUI,9 个跨平台桌面方案该怎么选
前端·javascript·rust·electron·openresty·前端开发工具
jay神2 小时前
基于 YOLOv8 的轴承缺陷检测(Web 版)
前端·人工智能·yolo
jay神2 小时前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat2 小时前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
miss3 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan3 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真3 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment3 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan4 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么4 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模