vue实现即开即用的AI对话打字机效果

废话不多说 直接上代码 读props 来引入组件即可

javascript 复制代码
<template>
  <div class="typewriter-text">
    {{ displayedText }}<span class="cursor">|</span>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'

const props = defineProps({
  // 完整的文字
  text: {
    type: String,
    default: ''
  },
  // 打字的速度
  speed: {
    type: Number,
    default: 50
  },
  // 是否自动开始
  autoStart: {
    type: Boolean,
    default: true
  },
  // 是否可见
  visible: {
    type: Boolean,
    default: true
  }
})

const displayedText = ref('')
const typewriterTimer = ref(null)

function startTypewriter () {
  displayedText.value = ''
  let index = 0
  if (typewriterTimer.value) {
    clearInterval(typewriterTimer.value)
  }
  typewriterTimer.value = setInterval(() => {
    if (index < props.text.length) {
      displayedText.value += props.text[index]
      index++
    } else {
      if (typewriterTimer.value) {
        clearInterval(typewriterTimer.value)
        typewriterTimer.value = null
      }
    }
  }, props.speed)
}

function resetTypewriter () {
  if (typewriterTimer.value) {
    clearInterval(typewriterTimer.value)
    typewriterTimer.value = null
  }
  displayedText.value = ''
}

// 监听visible,控制打字机效果的开始和重置
watch(() => props.visible, (newVal) => {
  if (newVal) {
    // autoStart为true的时候自动开始
    if (props.autoStart && props.text) {
      resetTypewriter()
      startTypewriter()
    }
  } else {
    // 重置
    resetTypewriter()
  }
}, { immediate: true })

// 监听文字,文字改变后重新开始
watch(() => props.text, () => {
  if (props.autoStart && props.visible && props.text) {
    resetTypewriter()
    startTypewriter()
  }
}, { immediate: false })

onMounted(() => {
  if (props.autoStart && props.visible && props.text) {
    startTypewriter()
  }
})

onUnmounted(() => {
  resetTypewriter()
})

defineExpose({
  start: startTypewriter,
  reset: resetTypewriter
})
</script>

<style lang="less" scoped>
.typewriter-text {
  font-size: 14px;
  line-height: 1.8;
  color: #333;
  min-height: 100px;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.typewriter-text .cursor {
  display: inline-block;
  margin-left: 2px;
  animation: blink 1s infinite;
  color: #3b82f6;
  font-weight: bold;
}

@keyframes blink {
  0%, 50% {
    opacity: 1;
  }
  51%, 100% {
    opacity: 0;
  }
}
</style>
相关推荐
裕波11 分钟前
Vue&ViteConf 2026 将于 7 月 18 日在上海举办,尤雨溪将现场发表主题演讲
vue.js·vite
IManiy12 分钟前
总结之Vibe Coding前端骨架
前端
小和尚敲木头16 分钟前
vue3 vite动态拼接图片路径
javascript
JS菌19 分钟前
AI Agent 沙箱双层防护体系:从权限过滤到内核隔离的完整实现
前端·人工智能·后端
Aphasia31129 分钟前
从输入URL到页面展示全流程
前端·面试
我叫黑大帅1 小时前
前端如何竖屏固定视口背景
前端·javascript·面试
abcy0712131 小时前
python pandas csv异步后台清洗前端优先返回成功信息
前端·python·pandas
不会敲代码11 小时前
我花了三天时间,终于把 Cookie、XSS、CSRF 和浏览器存储给整明白了
javascript·面试
IT_陈寒1 小时前
Vite这个坑我帮你踩了,动态导入居然这样才生效
前端·人工智能·后端
贩卖黄昏的熊1 小时前
flex 布局快速梳理
开发语言·javascript·css3·html5