🔥 Vue3 实现超丝滑打字机效果组件(可复用、高定制)
在前端开发中,打字机效果能极大提升页面的交互趣味性和视觉体验,比如 AI 聊天回复、个性化介绍页等场景都非常适用。本文将分享一个基于 Vue3 + Composition API 开发的高性能、高定制化打字机组件,支持打字/删除循环、光标闪烁、自定义样式等核心功能,且代码结构清晰、易于扩展。
🎯 组件特性
- ✅ 自定义打字速度、删除速度、循环延迟
- ✅ 支持光标显示/隐藏、闪烁效果开关
- ✅ 打字完成后自动删除(可选)+ 循环播放
- ✅ 完全自定义样式(字体、颜色、大小等)
- ✅ 暴露控制方法(开始/暂停),支持手动干预
- ✅ 无第三方依赖,纯原生 Vue3 实现
- ✅ 性能优化:组件卸载自动清理定时器,避免内存泄漏
📝 完整组件代码
<template><divclass="typewriter-container":style="fontsConStyle"><!--打字文本-逐字符渲染--><spanclass="typewriter-text"><span v-for="(char, index) in displayedText":key="index"class="character":data-index="index">{{char}}</span></span><!--光标-精准控制显示/闪烁--><span v-if="showCursor && isCursorVisible"class="cursor":class="{ 'blink': showBlinkCursor }"aria-hidden="true"/></div></template><script setup>import{ref,onMounted,onBeforeUnmount,computed,watch,watchEffect}from"vue";// 组件 Props 定义(带完整校验)constprops=defineProps({// 要显示的文本内容text:{type:String,required:true,default:""},// 打字速度(ms/字符)speed:{type:Number,default:80,validator:(value)=>value>0},// 是否显示光标showCursor:{type:Boolean,default:true},// 光标是否闪烁blinkCursor:{type:Boolean,default:true},// 是否自动开始打字autoStart:{type:Boolean,default:true},// 是否循环播放loop:{type:Boolean,default:false},// 循环延迟(打字完成后等待时间)loopDelay:{type:Number,default:1000,validator:(value)=>value>=0},// 容器样式(自定义字体、颜色等)fontsConStyle:{type:Object,default:()=>({fontSize:"2rem",fontFamily:"'Courier New', monospace",color:"#333",lineHeight:"1.5"})},// 是否开启删除效果deleteEffect:{type:Boolean,default:false},// 删除速度(ms/字符)deleteSpeed:{type:Number,default:30,validator:(value)=>value>0},// 字符入场动画开关charAnimation:{type:Boolean,default:true}});// 响应式状态constdisplayedText=ref("");// 当前显示的文本constcurrentIndex=ref(0);// 当前字符索引constisPlaying=ref(false);// 是否正在播放constisDeleting=ref(false);// 是否正在删除constisCursorVisible=ref(true);// 光标是否显示// 定时器标识(用于清理)letintervalId=null;lettimeoutId=null;letcursorTimer=null;// 计算属性:控制光标闪烁状态constshowBlinkCursor=computed(()=>{returnprops.blinkCursor&&!isDeleting.value&&(displayedText.value.length===props.text.length||displayedText.value.length===0);});// 工具函数:清除所有定时器constclearAllTimers=()=>{if(intervalId)clearInterval(intervalId);if(timeoutId)clearTimeout(timeoutId);if(cursorTimer)clearInterval(cursorTimer);intervalId=null;timeoutId=null;cursorTimer=null;};// 核心方法:开始打字conststartTyping=()=>{// 重置状态clearAllTimers();isPlaying.value=true;isDeleting.value=false;currentIndex.value=0;displayedText.value="";isCursorVisible.value=true;// 打字逻辑intervalId=setInterval(()=>{if(currentIndex.value<props.text.length){displayedText.value=props.text.substring(0,currentIndex.value+1);currentIndex.value++;}else{// 打字完成clearInterval(intervalId);isPlaying.value=false;// 循环逻辑if(props.loop){if(props.deleteEffect){timeoutId=setTimeout(startDeleting,props.loopDelay);}else{timeoutId=setTimeout(startTyping,props.loopDelay);}}}},props.speed);};// 核心方法:开始删除conststartDeleting=()=>{clearAllTimers();isDeleting.value=true;intervalId=setInterval(()=>{if(currentIndex.value>0){currentIndex.value--;displayedText.value=props.text.substring(0,currentIndex.value);}else{// 删除完成clearInterval(intervalId);isDeleting.value=false;// 循环打字if(props.loop){timeoutId=setTimeout(startTyping,props.loopDelay);}else{isCursorVisible.value=false;// 非循环模式下删除完成隐藏光标}}},props.deleteSpeed);};// 监听文本变化:自动重启打字(适配动态文本场景)watch(()=>props.text,(newText)=>{if(newText&&props.autoStart){startTyping();}},{immediate:true});// 初始化光标闪烁(非闪烁模式下固定显示)watchEffect(()=>{if(props.showCursor&&!cursorTimer){cursorTimer=setInterval(()=>{if(!showBlinkCursor.value){isCursorVisible.value=true;}else{isCursorVisible.value=!isCursorVisible.value;}},500);}});// 组件挂载:自动开始打字onMounted(()=>{if(props.autoStart&&props.text){startTyping();}});// 组件卸载:清理所有定时器(避免内存泄漏)onBeforeUnmount(()=>{clearAllTimers();});// 暴露组件方法(供父组件调用)defineExpose({start:startTyping,// 手动开始pause:clearAllTimers,// 暂停restart:()=>{// 重启clearAllTimers();startTyping();},isPlaying,// 当前播放状态isDeleting// 当前删除状态});</script><style scoped>/* 容器样式 - 适配行内/块级显示 */.typewriter-container{display:inline-flex;align-items:center;position:relative;font-size:inherit;line-height:inherit;font-family:inherit;white-space:pre-wrap;/* 支持换行符 */word-break:break-all;/* 防止长文本溢出 */}/* 文本容器 */.typewriter-text{display:inline;font-size:inherit;line-height:inherit;font-family:inherit;color:inherit;}/* 字符样式 - 入场动画 */.character{display:inline-block;animation:typeIn0.1s ease-out forwards;opacity:0;}/* 字符入场动画 */@keyframes typeIn{0%{transform:translateY(5px);opacity:0;}100%{transform:translateY(0);opacity:1;}}/* 光标样式 - 垂直居中优化 */.cursor{display:inline-block;width:2px;height:1.2em;/* 匹配字体高度 */background-color:currentColor;margin-left:2px;vertical-align:middle;position:relative;top:0;opacity:1;}/* 光标闪烁动画 */.cursor.blink{animation:blink 1s infinite step-end;}@keyframes blink{0%,100%{opacity:1;}50%{opacity:0;}}/* 禁用字符动画的样式 */:deep(.character){animation:none!important;opacity:1!important;}</style>🚀 核心优化点说明
1. 功能增强
- 新增
charAnimation属性:可开关字符入场动画,适配不同场景 - 支持动态文本:监听
text属性变化,文本更新自动重启打字 - 优化光标逻辑:非闪烁模式下光标固定显示,避免闪烁干扰
- 新增
restart方法:支持手动重启打字效果 - 文本换行支持:添加
white-space: pre-wrap,兼容带换行符的文本
2. 性能优化
- 定时器统一管理:所有定时器集中清理,避免内存泄漏
- 减少不必要渲染:通过
watchEffect精准控制光标定时器创建/销毁 - 样式优化:使用
currentColor继承文本颜色,光标颜色与文本一致 - 边界处理:添加
word-break: break-all,防止长文本溢出
3. 代码健壮性
- 完善 Prop 校验:所有数值类型添加范围校验,避免非法值
- 状态重置:每次开始打字前重置所有状态,避免多轮执行冲突
- 注释完善:关键逻辑添加注释,提升代码可读性
📖 使用示例
基础使用
<template><Typewriter text="Hello Vue3! 这是一个超丝滑的打字机效果组件✨"speed="50"/></template><script setup>importTypewriterfrom'./components/Typewriter.vue';</script>高级使用(循环+删除效果)
<template><div><Typewriter ref="typewriterRef"text="Vue3 打字机组件 | 支持循环删除 | 自定义样式":speed="60":deleteSpeed="40":loop="true":deleteEffect="true":loopDelay="1500":fontsConStyle="{fontSize:'1.5rem',color:'#409eff',fontFamily:'微软雅黑'}"/><button @click="handleRestart">重启打字</button></div></template><script setup>import{ref}from'vue';importTypewriterfrom'./components/Typewriter.vue';consttypewriterRef=ref();// 手动重启打字consthandleRestart=()=>{typewriterRef.value.restart();};</script>🎨 样式自定义说明
| 属性 | 说明 | 默认值 |
|---|---|---|
| fontSize | 字体大小 | 2rem |
| fontFamily | 字体 | ‘Courier New’, monospace |
| color | 文本颜色 | #333 |
| lineHeight | 行高 | 1.5 |
你可以通过fontsConStyle属性完全自定义组件样式,例如:
fontsConStyle:{fontSize:"18px",color:"#e6a23c",fontWeight:"bold",background:"#f5f7fa",padding:"10px 15px",borderRadius:"8px"}🛠️ 扩展方向
- 自定义字符动画:通过 Prop 传入动画类名,支持不同的字符入场效果
- 分段打字:支持数组形式的文本,分段打字+间隔
- 速度渐变:实现打字速度由快到慢/由慢到快的效果
- 暂停/继续:扩展暂停后继续打字的功能(记录当前索引)
- 结合 AI 流式响应:对接 AI 接口的流式返回,实时更新打字文本
📌 总结
这个打字机组件基于 Vue3 Composition API 开发,具备高复用性、高定制性的特点,核心优化点如下:
- 完善的定时器管理,避免内存泄漏
- 精准的状态控制,支持打字/删除/循环全流程
- 灵活的样式自定义,适配不同业务场景
- 暴露控制方法,支持父组件手动干预
组件可直接集成到 Vue3 项目中,适用于 AI 聊天、个人主页、产品介绍等需要打字机效果的场景,开箱即用!