跳转到内容

自定义事件封装

刀刀
0字
0分钟
2026/8/16

元素平滑上升

Vue 项目中通过封装自定义事件,实现盒子滚动到视口内时平滑上升的效果。

前置知识

  1. Element.animate() :创建一个新的 Animation 对象并应用于元素,运行动画。返回一个新建的 Animation 对象实例。

    接收两个参数:

    • 第一个参数:描述动画的 Keyframes 数组对象,包含一个或多个 CSS 样式和时间。
    • 第二个参数:描述动画的选项对象,包含动画属性,如持续时间 duration、延迟时间 delay、动画效果 ease 等。

    返回的动画对象实例可控制动画的暂停、播放、取消等操作。调用对应的 pause()play()cancel() 方法即可。

  2. [IntersectionObserver] :异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法,设计为异步以避免阻塞主线程。一个 IntersectionObserver 对象被创建后配置不可更改,但可在同一个观察者对象中配置监听多个目标元素。

思路

  1. 创建自定义事件,在 mounted 组件挂载生命周期钩子上,使用 Web Animation API 应用动画。写法为 el.animate(关键帧, 配置)。组件挂载后直接触发动画。
  2. 先让动画暂停,使用 IntersectionObserver 监听元素是否出现在视口内,出现则播放动画。在 unmounted 组件卸载生命周期钩子上,取消对元素的监听。
  3. mounted 生命周期钩子添加判断,如果元素已在视口内,则 return 不播放动画。
  4. 声明一个 WeakMap 变量 map,存储未播放过动画的元素,播放后从 map 内删除,避免重复播放。

代码实现

js
const DISTANCE = 100 // 初始y轴偏移位置
const DURATION = 500 // 动画持续时间
const map = new WeakMap()

// IntersectionObserver API
const ob = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      // 出现在视口中
      console.dir(entry)
      const animation = map.get(entry.target)
      animation && animation.play()
      ob.unobserve(entry.target) // 播放过后就不再播放动画
    }
  }
})

const isBelowViewPort = (el) => {
  const rect = el.getBoundingClientRect()
  return rect.top - window.innerHeight > 0
}

export default {
  mounted(el, binding) {
    // 判断当前元素是否在视口之上或者视口内,在的话不需要播放动画
    if (!isBelowViewPort(el)) return

    // 元素挂载后使用 Web Animation API 来应用动画。写法为el.animate(关键帧, 配置)
    const animation = el.animate(
      [
        {
          transform: `translateY(${DISTANCE}px)`,
          opacity: 0.5,
        },
        {
          transform: `translateY(0)`,
          opacity: 1,
        },
      ],
      {
        duration: DURATION,
        ease: 'ease-out',
        fill: 'forwards',
      },
    )

    animation.pause() // 先暂停动画,等待指令的触发
    map.set(el, animation)
    ob.observe(el) // 观察元素是否进入视口
  },
  unmounted(el) {
    ob.unobserve(el) // 元素卸载后断开观察
  },
}

总体效果

跳转预览:点击跳转

贡献者

The avatar of contributor named as duyidao duyidao
The avatar of contributor named as v_duyilin v_duyilin
The avatar of contributor named as 刀刀 刀刀

页面历史

刀刀博客累计访客 人;文档累计访问量共