vue3+ts封装打字机效果组件

完整代码

组件代码如下

<script setup lang="ts">
import { ref, watch } from 'vue'
const props = defineProps({
  data: {
    type: Array<string>,
    default: () => {
      '请输入内容'
    }
  }
})
// 用于判断打印并删除是否已经完成
const flag = ref<boolean>(true)
// 用于帮助打印语句的索引
const index = ref<number>(0)
const str1 = ref<string>(props.data[Math.floor(Math.random() * props.data.length)])
// 打印出来的句子
const typeWriterStr = ref<string>('')
// 打印的方法
const typing = () => {
  flag.value = false
  typeWriterStr.value += str1.value[index.value]
  index.value++
  if (str1.value.length !== index.value) {
    setTimeout(typing, 150)
  } else {
    // 添加清除的计时器
    startClear()
  }
}
// 开始清除
const startClear = () => {
  const cursorInterval = setInterval(() => {
    typeCursorFlag.value = !typeCursorFlag.value
  }, 300)
  setTimeout(() => {
    clearInterval(cursorInterval)
  }, 2000)
  setTimeout(clearTypeWriterStr, 2000)
}
// 打印完后清除的方法
const clearTypeWriterStr = () => {
  typeWriterStr.value = typeWriterStr.value.slice(0, index.value)
  index.value--
  if (index.value >= 0) {
    setTimeout(clearTypeWriterStr, 50)
  } else {
    flag.value = true
    str1.value = props.data[Math.floor(Math.random() * props.data.length)]
    index.value++
  }
}
// 启动开始打字的计时器
setTimeout(typing, 200)
// 控制光标的显示与隐藏
const typeCursorFlag = ref<boolean>(true)
watch(flag, (newVal) => {
  if (newVal) {
    setTimeout(typing, 200)
  }
})
</script>
<template>
  <div class="type-font">
    {{ typeWriterStr }}
    <span :class="typeCursorFlag ? [] : ['type-cursor']">|</span>
  </div>
</template>
<style lang="less" scoped>
.type-cursor {
  opacity: 0;
}
.type-font {
  font-size: 25px;
  color: #72b290;
  font-weight: bold;
}
</style>

组件使用如下,用法很简单只要穿如一个全是语句的数组即可

<Typeit :data="sayingData">Typeit>

成品效果如下:

详细代码分析

先定义一些需要用到的变量

// 用于帮助打印语句的索引
const index = ref<number>(0)
// 要被打印的句子
const str1 = ref<string>(props.data[Math.floor(Math.random() * props.data.length)])
// 打印出来的句子
const typeWriterStr = ref<string>('')

打印文字的方法

const typing = () => {
  flag.value = false
  typeWriterStr.value += str1.value[index.value]
  index.value++
  if (str1.value.length !== index.value) {
    setTimeout(typing, 150)
  } else {
    // 添加清除的计时器
    startClear()
  }
}

实际就是利用延迟函数依次去给索引自加然后从要被打印的语句挨个取字加给打印出来的就好,最后还需要根据索引和要打印的语句长度判断一下是否打印完,如果打印完则开始删除

删除文字的方法

const clearTypeWriterStr = () => {
  typeWriterStr.value = typeWriterStr.value.slice(0, index.value)
  index.value--
  if (index.value >= 0) {
    setTimeout(clearTypeWriterStr, 50)
  } else {
    flag.value = true
    str1.value = props.data[Math.floor(Math.random() * props.data.length)]
    index.value++
  }
}

与上边打印类似,根据索引依次删除即可,最后判断一下是否删除完,如果删除玩则随机产生数字换一个句子

等待一会在开始删除

const startClear = () => {
  const cursorInterval = setInterval(() => {
    typeCursorFlag.value = !typeCursorFlag.value
  }, 300)
  setTimeout(() => {
    clearInterval(cursorInterval)
  }, 2000)
  setTimeout(clearTypeWriterStr, 2000)
}

// class绑定写法如下
<span :class="typeCursorFlag ? [] : ['type-cursor']">|</span>

上边代码是为了让文字打印完后等待两秒在开始删除,如果立刻删除的话则会看不清句子,影响观感,同时还会改变typeCursorFlag的值利用hclass绑定以此来使光标闪烁

利用监听器来帮助群顶是否完成一轮打印删除

watch(flag, (newVal) => {
  if (newVal) {
    setTimeout(typing, 200)
  }
})

每次完成一轮之后都会改变flag的值,以此来告诉该下一次打印删除了

总结

遇到的问题的话,最主要的就是定时函数的问题,最开始我使用的是setInterval,结果因为作用域问题导致无法清除,自找了很多麻烦,最后改为了延时函数setTimeout,由此可见setTimeout要比setinterval好用一点
除了以上设置外,如果大家要是用到这段代码的话,文字样式,文字打印删除速度都可以改,甚至还可以二次加工做成组件传入的值

你可能感兴趣的:(javascript,前端,vue.js,typescript)