01 / VANILLA
原生页面组件 · Web Animations API
无额外依赖。返回清理函数,在页面切换或组件销毁时调用。
const target = document.querySelector("[data-motion='intro']");
let animation;
if (target && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
animation = target.animate(
[
{ opacity: 0, transform: "translateY(18px)" },
{ opacity: 1, transform: "translateY(0)" }
],
{ duration: 520, easing: "cubic-bezier(0.22,1,0.36,1)", fill: "both" }
);
}
export function cleanupIntro() {
animation?.cancel();
}
02 / REACT
React · useEffect 生命周期
使用 ref 定位元素,effect cleanup 会在依赖变化和卸载时运行。
import { useEffect, useRef } from "react";
export function IntroPanel() {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const animation = el.animate(
[{ opacity: 0, transform: "translateY(16px)" },
{ opacity: 1, transform: "translateY(0)" }],
{ duration: 480, easing: "ease-out", fill: "both" }
);
return () => animation.cancel();
}, []);
return <section ref={ref}>真实业务内容</section>;
}
03 / VUE 3
Vue 3 · onMounted / onBeforeUnmount
在 DOM 挂载后启动,卸载前清理动画;避免对尚未渲染的节点操作。
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
const panel = ref(null);
let animation;
onMounted(() => {
if (!panel.value ||
matchMedia("(prefers-reduced-motion: reduce)").matches) return;
animation = panel.value.animate(
[{ opacity: 0, transform: "translateX(20px)" },
{ opacity: 1, transform: "translateX(0)" }],
{ duration: 420, easing: "ease-out", fill: "both" }
);
});
onBeforeUnmount(() => animation?.cancel());
</script>
<template><section ref="panel">真实业务内容</section></template>
04 / ENGINE CHOICE
什么时候选哪个引擎
根据复杂度与项目已有依赖选择,不要为一个简单入场效果额外引入整套引擎。
Web Animations API
轻量入场、淡出、位移;浏览器原生支持。
GSAP
复杂时间线、跨元素编排、ScrollTrigger 场景。
Motion
React / vanilla 交互、手势与状态驱动动效。
Three.js
3D 场景与粒子可视化;注意 GPU、帧率和电量成本。