打字机效果指令(超级详细)

本文最后更新于:2023年11月5日 晚上

基础使用

注册(vue2为例)

1
2
3
4
import Vue from 'vue'
import write from "./write"

Vue.directive('write', write)

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
export default {
data () {
return {
text: '我还是我'
}
},
}
</script>

<template>
<div>
<button @click="text='你还是你吗'">改变文字</button>
<p v-write:200.2000.400="text" />
<p v-write:150.1000="'这是一段超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级超级长的文字'" />
</div>
</template>

解释:

200ms打印一个字符,最开始等待2400ms(2000ms + 400ms)才开始打印

冒号像栏杆就表示打字的间隔,点就是等,是不是很好记😂

write.js

这里使用到封装的一个工具函数,useFlicker.js,见:封装虚拟光标闪烁效果

vue2 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* @author Xin-FAS
*/
import { useFlicker } from '@/useFlicker'

// 存储同时存在的打字效果
const mapStore = new Map()
const write = {
// 操作文字打字效果,存储在这个位置主要是给全部生命周期使用
async bind (el, { arg, modifiers, value }) {
if (!value) return
// 累加等待值
const delay = Object
.entries(modifiers).map(v => +v[0])
.reduce((count, num) => count + num, 0)
// 这里一定要判断undefined,否则arg=0会赋值150,ES11的??可以解决
const duration = (arg === undefined) ? 150 : +arg
// 初始打字化效果,并开始闪烁
const flickerHandler = useFlicker(el)
flickerHandler.startFlicker()
let delayTime
// 开始等待
await new Promise(res => delayTime = setTimeout(res, delay))
// 定时器开始打字
const innerHTMLArr = value.trim().split('')
const lastIndex = innerHTMLArr.length - 1
let activeIndex = 0
const textInterval = setInterval(() => {
flickerHandler.pushText({
value: innerHTMLArr[activeIndex++],
next: activeIndex <= lastIndex
})
if (activeIndex > lastIndex) clearInterval(textInterval)
// 关闭打字
}, duration)
// 存入全局函数
const handlerEvent = {
flickerHandler,
textInterval,
delayTime
}
// 创建仓库key并存入,随机防止重复
const mapKey = 'map-key' + (Math.random() * 1000).toFixed(5)
mapStore.set(mapKey, handlerEvent)
el.setAttribute('map-key', mapKey)
},
update (el, binding) {
const { value, oldValue } = binding
// 防止其他地方的刷新
if (value === oldValue) return
// 结束
write.unbind(el)
// 重新开始
write.bind(el, binding)
},
unbind (el) {
// 获取元素上的操作函数
const mapKey = el.getAttribute('map-key')
const handlerEvent = mapStore.get(mapKey)
// 清空当前元素上的所有定时器和效果
handlerEvent.flickerHandler.closeFlicker()
clearInterval(handlerEvent.textInterval)
clearTimeout(handlerEvent.delayTime)
// 开始清空
mapStore.delete(mapKey)
el.removeAttribute('map-key')
}
}
export default write

vue3 版本

没有ts就只是生命周期的区别

  1. bind改为了mounted

  2. unbind改为了unmounted

  3. update改为了updated

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* @author Xin-FAS
*/
import { useFlicker } from '@/views/useFlicker'

// 存储同时存在的打字效果
const mapStore = new Map()
const write = {
// 操作文字打字效果,存储在这个位置主要是给全部生命周期使用
async mounted (el, { arg, modifiers, value }) {
if (!value) return
// 累加等待值
const delay = Object
.entries(modifiers).map(v => +v[0])
.reduce((count, num) => count + num, 0)
// 这里一定要判断undefined,否则arg=0会赋值150,ES11的??可以解决
const duration = (arg === undefined) ? 150 : +arg
// 初始打字化效果,并开始闪烁
const flickerHandler = useFlicker(el)
flickerHandler.startFlicker()
let delayTime
// 开始等待
await new Promise(res => delayTime = setTimeout(res, delay))
// 定时器开始打字
const innerHTMLArr = value.trim().split('')
const lastIndex = innerHTMLArr.length - 1
let activeIndex = 0
const textInterval = setInterval(() => {
flickerHandler.pushText({
value: innerHTMLArr[activeIndex++],
next: activeIndex <= lastIndex
})
if (activeIndex > lastIndex) clearInterval(textInterval)
// 关闭打字
}, duration)
// 存入全局函数
const handlerEvent = {
flickerHandler,
textInterval,
delayTime
}
// 创建仓库key并存入,随机防止重复
const mapKey = 'map-key' + (Math.random() * 1000).toFixed(5)
mapStore.set(mapKey, handlerEvent)
el.setAttribute('map-key', mapKey)
},
updated (el, binding) {
const { value, oldValue } = binding
// 防止其他地方的刷新
if (value === oldValue) return
// 结束
write.unmounted(el)
// 重新开始
write.mounted(el, binding)
},
unmounted (el) {
// 获取元素上的操作函数
const mapKey = el.getAttribute('map-key')
const handlerEvent = mapStore.get(mapKey)
// 清空当前元素上的所有定时器和效果
handlerEvent.flickerHandler.closeFlicker()
clearInterval(handlerEvent.textInterval)
clearTimeout(handlerEvent.delayTime)
// 开始清空
mapStore.delete(mapKey)
el.removeAttribute('map-key')
}
}
export default write

打字机效果指令(超级详细)
https://xin-fas.github.io/2023/08/23/打字机效果指令(超级详细)/
作者
Xin-FAS
发布于
2023年8月23日
更新于
2023年11月5日
许可协议