实现"选中表格项将元素加入集合"的动画效果

vue3 element-plus gsap

获取动画起止点

element plus中 这样写会构造一个选择器列

js 复制代码
<el-table-column type="selection"/>

选中事件为@select 参数1是当前选中的所有行 参数2是变化的行(选中或没选中) 并不能得到用户点击的位置信息

因此这里需要一点小寄巧 在另一个表格列加入一个用于定位的元素

xml 复制代码
  <el-table-column>
    <template v-slot="{ row }">
      <span class="hidden" :id="row.id"></span>
      <!-- 其他列的正常内容 -->
    </template>
  </el-table-column>

然后可以通过被点击行的id 取得用户点击的那个checkbox

js 复制代码
document.querySelector(
    `.el-table__row:has(>.el-table__cell>.cell>#${id})>td:first-child .el-checkbox`,
  )

需要注意的是querySelector需要一个合法的css选择器

一些id会导致css选择器非法 例如useId生成的id :S1:

动画终点dom通过ref获得即可

创建动画

首先需要一个临时创建dom的函数

这篇文章的基础上 为contanier增加z-index 确保动画能覆盖在所有dom上面

js 复制代码
import { createVNode, render } from 'vue'

/** 命令式临时渲染一个组件 */
export const tempRender = (comp, ...args) => {
  const container = document.createElement('div')
  container.style.position = 'fixed'
  container.style.zIndex = '9999'
  document.body.append(container)
  const dialogNode = createVNode(comp, { ...args })
  render(dialogNode, container)
  function destory () {
    render(null, container)
    container.remove()
  }
  return destory
}

然后就可以用gsap创建动画

先在main.js注册插件

js 复制代码
import gsap from 'gsap'
import MotionPathPlugin from 'gsap/MotionPathPlugin'

gsap.registerPlugin(MotionPathPlugin)

然后实际创建动画

js 复制代码
async function startAnime (id) {
  const startDom = //
  const endDom = //
  const { top: startTop, left: startLeft } = getCenterPosition(startDom)
  const { top: endTop, left: endLeft } = getCenterPosition(endDom)

  const animePointId = `__animePoint${Date.now()}`
  const duration = 0.8 // 秒
  const bezier = 'cubic-bezier(0.30, 1.00, 0.80, 1.20)'
  const path = getPath(startTop, startLeft, endTop, endLeft, bezier)
  const [d, bg] = ['1rem', '#6f65cc']
  const destory = tempRender('div', {
    id: animePointId,
    class: 'fixed rounded-full',
    style: `top:${startTop}px;left:${startLeft}px;width:${d};height:${d};background-color:${bg};`,
  })
  const animePoint = document.querySelector(`#${animePointId}`)
  await gsap.to(animePoint, { motionPath: path, duration, ease: 'power1.in' })
  destory()
  await gsap.to(endDom, { scale: 1.2, duration: 0.15 })
  await gsap.to(endDom, { scale: 1, duration: 0.1 })
}
/**
 * 获取一个dom的左上角相对html的位置
 * @param {HTMLElement} dom
 */
function getCenterPosition (dom) {
  const { top, left } = dom.getBoundingClientRect()
  const { scrollX, scrollY } = window
  return {
    top: top + scrollX,
    left: left + scrollY,
  }
}
/**
 * 根据起止点缩放贝塞尔曲线
 */
function getPath (startTop, startLeft, endTop, endLeft, bezier) {
  const x = endLeft - startLeft
  const y = endTop - startTop
  const [x1, y1, x2, y2] = bezier
    .match(/cubic-bezier\((.*)\)/)[1]
    .split(/\s?,\s?/)
    .map(Number)
  return `M0,0 C${x1 * x},${y1 * y} ${x2 * x},${y2 * y} ${x},${y}`
}

实际效果就是淘宝、美团加入购物车的那个动画 小球抛出 然后按钮闪一下

理论上需要构造抛物线 但是实现需要x平移 y按上抛变化 比较麻烦

所以用贝塞尔曲线模拟一下就行了 反正差不多
cubic-bezier.tupulin.com/ 这个网站可以直接把调试贝塞尔曲线

相关推荐
QTX1873020 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下27 分钟前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
三翼鸟数字化技术团队1 小时前
Vue自定义指令最佳实践教程
前端·vue.js
猿榜2 小时前
js逆向-喜某拉雅Xm-Sign参数解密
javascript
转转技术团队2 小时前
代码变更暗藏危机?代码影响范围分析为你保驾护航
前端·javascript·node.js
Spark2382 小时前
关于vue3整合tiptap的slash菜单的ts支持
vue.js
Mintopia2 小时前
Node.js高级实战:自定义流与Pipeline的高效数据处理 ——从字母生成器到文件管道的深度解析
前端·javascript·node.js
Mintopia2 小时前
Three.js深度解析:InstancedBufferGeometry实现动态星空特效 ——高效渲染十万粒子的底层奥秘
前端·javascript·three.js
随笔记2 小时前
Flex布局下,label标签设置宽度依旧对不齐,完美解决(flex-shrink属性)
javascript·css·vue.js
樊小肆2 小时前
实战!从 0 到 1 搭建 H5 AI 对话页面
前端·vue.js