Vue中引入Codepen打字效果脚本失效问题及解决方案求助
Vue中实现打字效果失效的问题与解决方法
问题描述
将Codepen上的打字效果代码复制到Vue文件后,仅显示“Im A'”及闪烁光标,文字切换效果未触发,推测脚本未运行。以下是用户提供的原始代码:
原始HTML
<div class="container"> <p>Im A'<span class="typed-text"></span><span class="cursor"> </span></p> </div>
原始CSS
p { overflow: hidden; } .container p span.typed-text { font-weight: normal; color: white; text-shadow:1px 1px 1px yellow; } .container p span.cursor { display: inline-block; background-color: #ccc; margin-left: 0.1rem; width: 3px; animation: blink 1s infinite; } .container p span.cursor.typing { animation: none; } @keyframes blink { 0% { background-color: #ccc; } 49% { background-color: #ccc; } 50% { background-color: transparent; } 99% { background-color: transparent; } 100% { background-color: #ccc; } }
原始JS(存在语法错误)
const typedTextSpan = document.querySelector(".typed-text"); const cursorSpan = document.querySelector(".cursor"); const textArray = ["web developer", "UI/UX Designer", "Front End"]; const typingDelay = 200; const erasingDelay = 100; const newTextDelay = 2000; // Delay between current and next text let textArrayIndex = 0; let charIndex = 0; function type() { if (charIndex < textArray[textArrayIndex].length) { if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing"); typedTextSpan.textContent += textArray[textArrayIndex].charAt(charIndex); charIndex++; setTimeout(type, typingDelay); } else { cursorSpan.classList.remove("typing"); setTimeout(erase, newTextDelay); } } function erase() { if (charIndex > 0) { if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing"); typedTextSpan.textContent = textArray[textArrayIndex].substring(0, charIndex-1); charIndex--; setTimeout(erase, erasingDelay); } else { cursorSpan.classList.remove("typing"); textArrayIndex++; if(textArrayIndex>=textArray.length) textArrayIndex=0; setTimeout(type, typingDelay + 1100); // 缺少函数闭合大括号
Vue与普通HTML中JS运行的核心区别
- DOM渲染时机不同:普通HTML脚本在DOM加载完成后直接执行,而Vue组件的DOM是异步渲染的,直接用
document.querySelector可能无法获取到组件内的元素(组件尚未挂载)。 - 作用域隔离:Vue组件有独立作用域,全局脚本无法直接访问组件内DOM,且直接操作DOM不符合Vue响应式设计理念。
- 生命周期约束:Vue组件有明确的生命周期钩子,脚本需在合适的钩子(如
mounted)中执行,确保DOM已渲染完成。 - 语法错误影响:原始JS中
erase函数缺少闭合大括号,会直接导致脚本终止运行。
正确实现方法
方法一:适配Vue生命周期的原生JS改造
将脚本放入Vue组件的mounted钩子,使用组件内DOM查询替代全局查询,同时修复语法错误:
<template> <div class="container"> <p>Im A'<span class="typed-text"></span><span class="cursor"> </span></p> </div> </template> <script> export default { mounted() { const typedTextSpan = this.$el.querySelector(".typed-text"); const cursorSpan = this.$el.querySelector(".cursor"); const textArray = ["web developer", "UI/UX Designer", "Front End"]; const typingDelay = 200; const erasingDelay = 100; const newTextDelay = 2000; let textArrayIndex = 0; let charIndex = 0; function type() { if (charIndex < textArray[textArrayIndex].length) { if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing"); typedTextSpan.textContent += textArray[textArrayIndex].charAt(charIndex); charIndex++; setTimeout(type, typingDelay); } else { cursorSpan.classList.remove("typing"); setTimeout(erase, newTextDelay); } } function erase() { if (charIndex > 0) { if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing"); typedTextSpan.textContent = textArray[textArrayIndex].substring(0, charIndex-1); charIndex--; setTimeout(erase, erasingDelay); } else { cursorSpan.classList.remove("typing"); textArrayIndex++; if(textArrayIndex >= textArray.length) textArrayIndex = 0; setTimeout(type, typingDelay + 1100); } } // 启动打字效果 type(); // 组件销毁时清理定时器,避免内存泄漏 this.$once('hook:beforeDestroy', () => { // 可收集定时器ID并逐一清除,简单场景可省略 }); } } </script> <style scoped> p { overflow: hidden; } .container p span.typed-text { font-weight: normal; color: white; text-shadow:1px 1px 1px yellow; } .container p span.cursor { display: inline-block; background-color: #ccc; margin-left: 0.1rem; width: 3px; animation: blink 1s infinite; } .container p span.cursor.typing { animation: none; } @keyframes blink { 0% { background-color: #ccc; } 49% { background-color: #ccc; } 50% { background-color: transparent; } 99% { background-color: transparent; } 100% { background-color: #ccc; } } </style>
方法二:Vue响应式实现(更推荐)
通过Vue响应式数据控制文本内容与光标状态,符合Vue开发规范:
<template> <div class="container"> <p>Im A'<span class="typed-text">{{ currentText }}</span><span :class="['cursor', { typing: isTyping }]"> </span></p> </div> </template> <script> export default { data() { return { textArray: ["web developer", "UI/UX Designer", "Front End"], currentText: "", textIndex: 0, charIndex: 0, isTyping: false, typingDelay: 200, erasingDelay: 100, newTextDelay: 2000 }; }, mounted() { this.startTyping(); }, methods: { startTyping() { this.type(); }, type() { this.isTyping = true; if (this.charIndex < this.textArray[this.textIndex].length) { this.currentText += this.textArray[this.textIndex].charAt(this.charIndex); this.charIndex++; setTimeout(() => this.type(), this.typingDelay); } else { this.isTyping = false; setTimeout(() => this.erase(), this.newTextDelay); } }, erase() { this.isTyping = true; if (this.charIndex > 0) { this.currentText = this.textArray[this.textIndex].substring(0, this.charIndex - 1); this.charIndex--; setTimeout(() => this.erase(), this.erasingDelay); } else { this.isTyping = false; this.textIndex = (this.textIndex + 1) % this.textArray.length; setTimeout(() => this.type(), this.typingDelay + 1100); } } }, beforeDestroy() { // 清理所有定时器,避免内存泄漏 const timerCount = setTimeout(() => {}, 0); for (let i = 0; i < timerCount; i++) { clearTimeout(i); } } }; </script> <style scoped> p { overflow: hidden; } .container p span.typed-text { font-weight: normal; color: white; text-shadow:1px 1px 1px yellow; } .container p span.cursor { display: inline-block; background-color: #ccc; margin-left: 0.1rem; width: 3px; animation: blink 1s infinite; } .container p span.cursor.typing { animation: none; } @keyframes blink { 0% { background-color: #ccc; } 49% { background-color: #ccc; } 50% { background-color: transparent; } 99% { background-color: transparent; } 100% { background-color: #ccc; } } </style>
内容的提问来源于stack exchange,提问作者adityamms
相关产品推荐
相关产品推荐

