开发手记:Vue 3 卷轴展开动画组件的实现与思考
开发手记:Vue 3 卷轴展开动画组件的实现与思考
📜 前言
最近在开发一个文化类网站,需要实现一个传统中国画卷轴展开的动画效果。最初以为只是简单的左右滑动,但实际开发过程中遇到了不少问题,比如底图如何跟随画轴动态展开、动画同步控制等。最终,我实现了一个可复用的 Vue 3 组件,并在这个过程中学到了不少 CSS 动画和 Vue 响应式编程的技巧。
今天就来分享一下这个组件的开发历程、技术实现、踩坑记录,以及最终的优化方案。
目前已经打包成了vue3的组件,具体用法可以看源码地址,现在已经发布在npm上:
安装npm i vue3-handscroll-animation
即可
🎯 需求分析
- 核心功能
-
画轴动画:左右两个画轴从中间向两侧展开
-
底图动态显示:背景图片随画轴展开逐步呈现(而不是一开始就完整显示)
-
可定制化:支持自定义尺寸、动画时间、背景图
-
插槽支持:允许在卷轴中间插入任意内容
- 技术选型
-
Vue 3 (简洁的 Composition API)
-
纯 CSS 动画(避免引入额外库,保持轻量)
-
clip-path 裁剪(控制底图显示范围)
🔧 开发历程
初始版本:仅画轴动画
最开始,我只实现了画轴的移动动画:
<template><div class="handscroll-container"><!-- 左侧画轴 --><div class="scroll scroll-left" :class="{ 'left-scroll-animation': isOpened }"><img :src="leftScrollImage" /></div><!-- 右侧画轴 --><div class="scroll scroll-right" :class="{ 'right-scroll-animation': isOpened }"><img :src="rightScrollImage" /></div></div>
</template><style>
.left-scroll-animation {animation: left-scroll 2s forwards;
@keyframes left-scroll {from { transform: translateX(50%); }to { transform: translateX(0); }
</style>
1. 问题:
✅ 画轴可以正常展开
❌ 底图一开始就完整显示,没有跟随画轴动态呈现
思路:尝试 clip-path 裁剪底图
为了让底图跟随画轴展开,我尝试用 clip-path: inset() 控制显示范围:
.scroll-bg-img {clip-path: inset(0 50% 0 50%); / 初始只显示中间 /
.scroll-bg-img-center-an {animation: bg-reveal 2s forwards;
@keyframes bg-reveal {to { clip-path: inset(0 0 0 0); } / 最终完全显示 /
2.问题:
✅ 底图可以动态展开
❌ 动画不同步:画轴移动和底图展开速度不一致
解决方案:
统一动画时间(通过 props.animationDuration 控制)
使用相同的缓动函数(ease)
最终优化:同步动画 + 性能优化
为了让动画更流畅,我做了以下优化:
-
使用 transform 代替 left/right(GPU 加速)
-
避免重复计算 DOM 尺寸(用 Vue 的 computed 缓存)
-
支持外部触发动画(defineExpose 暴露 play 方法)
<script setup>
const play = () => {isOpened.value = true;
};
defineExpose({ play }); // 允许父组件调用
</script>
💡 关键技术与思考
1. clip-path 的妙用
inset() 可以裁剪元素的显示区域
初始状态:clip-path: inset(0 50% 0 50%)(只显示中间)
动画结束:clip-path: inset(0 0 0 0)(完全显示)
2. CSS 变量与 Vue 的动态绑定
.scroll-image {width: v-bind(scrollImageWidth); / 动态绑定 props /
}
Vue 3 的 v-bind 在
画轴移动(transform)
底图裁剪(clip-path)
使用相同的 animationDuration 确保同步
🚀 最终效果
✅ 画轴平滑展开
✅ 底图跟随动态显示
✅ 支持自定义内容插槽
✅ 高性能(纯 CSS 动画)
示例代码:
<HandScroll width="800px" height="400px":animationDuration="2000"
<h1>《千里江山图》</h1><p>这是一幅传世名画...</p>
</HandScroll>
📌 总结与展望
这个组件从初版到优化,经历了多次调整,最终实现了高性能、可定制、易用的卷轴动画。
未来优化方向:
支持手势滑动展开(结合 @touchstart / @mousedown)
预加载背景图(避免动画开始时图片未加载完成)
更复杂的缓动效果(考虑引入 GSAP)
如果你也在做类似的动画效果,希望这篇分享对你有帮助!🎨
欢迎讨论 & 优化建议! 🚀