打字机效果文本
2022年8月23日
打字机效果文本
|
代码
详情
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
const TimeoutPromise = async (ms?: number) => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, ms)
})
}
interface Props {
texts: string[]
speed?: number | 'fast' | 'slow'
loop?: boolean
clearMode?: 'clear' | 'backspace'
delay?: 'default' | number
}
const props = withDefaults(defineProps<Props>(), {
speed: 300,
loop: false,
clearMode: 'backspace',
delay: 'default'
})
const curTextId = ref(0)
const curTextPosition = ref(0)
let speed = 300
const cursor = ref('|')
const content = computed(() => {
return `${props.texts[curTextId.value]
.slice(0, curTextPosition.value)
.split('<')
.join('<br />')}${cursor.value}`
})
const print = () => {
if (curTextPosition.value < props.texts[curTextId.value].length) {
curTextPosition.value += 1
}
}
const printBack = async () => {
if (curTextPosition.value > 0) {
if (props.clearMode === 'backspace'){
await TimeoutPromise(speed / 2)
}
curTextPosition.value -= 1
await printBack()
}
}
// 模拟电脑光标闪动,0.53秒闪一次
const cursorFlash = () => {
setTimeout(() => {
cursor.value = ' '
}, 100)
setTimeout(() => {
cursor.value = '|'
}, 630)
}
const printLoop = async () => {
// 打字
await new Promise<void>((resolve) => {
const printInterval = setInterval(() => {
print()
if (curTextPosition.value >= props.texts[curTextId.value].length) {
clearInterval(printInterval)
resolve()
}
}, speed)
})
// 打字结束后光标闪动
// 设置setInterval前调用一次,立即执行一次,之后定期循环执行
cursorFlash()
const cursorFlashInterval = setInterval(cursorFlash, 1060)
let delay = (props.texts[curTextId.value].length - 1) * speed
if (!Number.isNaN(Number(props.delay))) {
delay = Number(props.delay)
}
await TimeoutPromise(delay)
// 切换到下一句或结束循环
if (curTextId.value < props.texts.length - 1) {
clearInterval(cursorFlashInterval)
await printBack()
curTextId.value += 1
curTextPosition.value = 0
printLoop()
} else if (props.loop) {
clearInterval(cursorFlashInterval)
await printBack()
curTextId.value = 0
printLoop()
}
}
onMounted(async () => {
if (Number.isNaN(Number(props.speed))) {
if (props.speed === 'fast') {
speed = 100
} else if (props.speed === 'slow') {
speed = 500
}
} else {
speed = Number(props.speed)
}
printLoop()
})
</script>
<template>
<p v-html="content"></p>
</template>
使用
示例
// texts(显示内容)必须设置,类型为字符串数组,多段文本依次显示
<TypeText :texts="['这是第一段文字','这是第二段']" />
// 在显示内容中使用<换行
<TypeText :texts="['这是<多行文字']" />
// 循环显示
<TypeText :texts="['这是第一段文字','这是第二段']" :loop="true" />
// 切换显示段落时使用清屏模式擦除现有文字
<TypeText :texts="['这是第一段文字','这是第二段']" clearMode="clear" />
// 等待1s后切换显示段落
<TypeText :texts="['这是第一段文字','这是第二段']" :delay="1000" />
// 设置显示速度
<TypeText :texts="['这是第一段文字','这是第二段']" speed="fast" />
API
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
texts | 显示内容 | string[] | - |
loop | 是否循环显示 | boolean | false |
clearMode | 切换显示段落的模式 | 'clear' | 'backspace' | 'backspace' |
delay | 切换显示段落的延迟,单位为ms | number | 'default' | 'default' |
speed | 显示速度,'fast' 和'slow' 对应的速度值分别为100 和500 | number | 'fast' | 'slow' | 300 |