Vue3自定义动画指令的封装&注册&使用

说明

该指令用于实现页面元素滚动到窗口可视范围时,执行动画,并且执行一次。动画为从底向上的移入效果,可以指定距离和动画的持续时间,不指定则为默认设置的距离与时间

当书写指令后打开页面没效果先想一下是不是一开始就在可视范围了

当指定的距离是负数时将会从上到下移入

指令源代码

const DISTANCE = 100; // 距离
const ANIMATIONTIME = 500; // 500毫秒
let distance: number | null = null,
  animationtime: number | null = null;
const map = new WeakMap();
const ob = new IntersectionObserver((entries) => {
  for (const entrie of entries) {
    if (entrie.isIntersecting) {
      const animation = map.get(entrie.target);
      if (animation) {
        animation.play();
        ob.unobserve(entrie.target);
      }
    }
  }
});

function isBelowViewport(el: HTMLElement) {
  const rect = el.getBoundingClientRect();
  return rect.top - (distance || DISTANCE) > window.innerHeight;
}

export default {
  mounted(el: HTMLElement, binding: any) {
    if (binding.value) { // 传值?
      console.log(binding.value);// 打印
      distance = binding.value.px;// 接收指定距离
      animationtime = binding.value.time;// 接收指定时间
    }
    if (!isBelowViewport(el)) {
      return;
    }
    const animation = el.animate(
      [
        {
          opacity: 0,
          transform: `translateY(${distance || DISTANCE}px)`,
        },
        {
          opacity: 1,
          transform: `translateY(0px)`,
        },
      ],
      {
        duration: animationtime || ANIMATIONTIME,
        fill: "forwards",
        easing: "ease-in-out",
      }
    );
    animation.pause();
    map.set(el, animation);
    ob.observe(el);
  },

  unmounted(el:HTMLElement) {
    ob.unobserve(el);
  },
};


全局注册 main.ts

import { createApp } from 'vue'
import App from './App.vue'
import top from './util/toTop.ts'

const app = createApp(App)
app.directive('top', top) // 注意要在const app 之后因为你要使用它
app.mount('#app')

不指定距离与时间正常使用

<template>
<h1 v-top>标题内容</h1>
</template>

指定距离与时间定制使用

<template>
<h1 v-top="{ px: 200, time: 2000 }">标题内容</h1>
</template>