封装虚拟光标闪烁效果

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

直接上使用

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
<script>
import { useFlicker } from './useFlicker'

export default {
data () {
return {
value: '',
flickerInstance: '',
duration: void 0,
next: true
}
},
mounted () {
this.flickerInstance = useFlicker(this.$refs.target)
}
}
</script>

<template>
<div>
<input type="text" v-model="value" placeholder="添加文字" />
<input type="number" v-model="duration" placeholder="添加时长(毫秒,默认0)" />
<input type="radio" id="select1" :value="true" v-model="next" />
<label for="select1">操作后继续闪烁</label>
<input type="radio" id="select2" :value="false" v-model="next" />
<label for="select2">操作后结束闪烁</label>
<div>
<button @click="flickerInstance.pushText({ value, duration, next })">添加文字</button>
<button @click="flickerInstance.popText(next)">移除一个文字</button>
<button @click="flickerInstance.clearText(next)">清空文字</button>
<button @click="flickerInstance.startFlicker()">开始闪烁效果</button>
<button @click="flickerInstance.closeFlicker()">关闭闪烁效果</button>
</div>
<div style="display: flex">
<span ref="target">这里会被清空</span>
<span>占位文本</span>
</div>
<div>占位文本</div>
</template>

<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
</style>

useFlicker:第一个参数传递元素对象,第二个传递闪烁光标,默认(_

API:

  1. pushText:添加文字,可以传入一个对象,参数如下:
    1. value:要添加的文字
    2. duration:添加value文字时总时长是多少
    3. easing:可自定义文字的打印速度曲线,默认为 x => x,即匀速(这个曲线函数x范围为 0 - 1,返回范围也是0 - 1,更多曲线函数查看:https://easings.net/)
    4. next:打字完成后是否继续闪烁效果
  2. popText:移除最后一个文字,可以传入布尔值,功能同1-4
  3. clearText:清空文字,可以传入布尔值,功能同1-4
  4. startFlicker:开始闪烁
  5. closeFlicker:关闭闪烁

useFlicker.js

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* @author Xin-FAS
*/
const useFlicker = (el, val = '_') => {
// 闪烁元素,文字元素,闪烁定时器,取消闪烁定时器,打字定时器,初始还原定时器
let flickerNode,
textNode,
intervalInstance,
timeoutInstance,
typingInstance,
initStateInstance

// 初始化
const initFlicker = () => {
// 清空元素
el.innerHTML = ''
// 添加闪烁元素
flickerNode = document.createElement('span')
flickerNode.style.opacity = '0'
flickerNode.style.transition = 'opacity 300ms'
flickerNode.style.willChange = 'opacity'
// 添加文字元素
textNode = document.createElement('span')
// 添加一层span,防止布局被破坏
const span = document.createElement('span')
span.appendChild(textNode)
span.appendChild(flickerNode)
el.appendChild(span)
}
initFlicker()
// 普通状态
const setInitialState = () => flickerNode.style.opacity = '0'
// 闪烁状态
const setFlickerState = () => flickerNode.style.opacity = '1'
// 在打字状态做一些事情
const typingHandler = (fn, next = true) => {
// 关闭闪烁定时器
clearInterval(intervalInstance)
// 执行
fn()
// 设置为闪烁状态
setFlickerState()
// 打字结束后还原
clearTimeout(initStateInstance)
initStateInstance = setTimeout(setInitialState, 400)
// 是否继续闪烁,继续则不清空闪烁内容
if (next) startFlicker()
else flickerNode.innerHTML = ''
}
// 开始闪烁效果
const startFlicker = () => {
// 保证只存在一个闪烁定时器
clearTimeout(timeoutInstance)
clearInterval(intervalInstance)
flickerNode.innerHTML = val
intervalInstance = setInterval(() =>
timeoutInstance = (setFlickerState(), setTimeout(setInitialState, 400))
, 1100)
}
// 关闭闪烁效果
const closeFlicker = () => {
clearInterval(intervalInstance)
// 清空内容
flickerNode.innerHTML = ''
}
// 清空文字,next:清空后是否继续闪烁
const clearText = next => typingHandler(() => textNode.innerText = '', next)
// 添加文字
const pushText = ({
value,
duration = 0,
easing = x => x,
next
}) => {
if (!value) return
const valCount = value.length
// 一个递归实现根据函数间隔打字
const runTimeout = (active = 0, beforeTime = 0) => {
active = ++active
if (active > valCount) return
const delay = easing(active / valCount) * duration - beforeTime
typingInstance = setTimeout(() => {
// 添加文字,只在最后一位时决定next
typingHandler(() => textNode.innerText += value[active - 1], active < valCount || next)
runTimeout(active, beforeTime + delay)
}, delay)
}
runTimeout()
}
// 移除一个文字,next:在移除后是否继续闪烁
const popText = next => typingHandler(() => textNode.innerText = textNode.innerText.slice(0, -1), next)

return {
startFlicker,
closeFlicker,
clearText,
pushText,
popText
}
}

export { useFlicker }

封装虚拟光标闪烁效果
https://xin-fas.github.io/2023/09/02/封装虚拟光标闪烁效果/
作者
Xin-FAS
发布于
2023年9月2日
更新于
2023年11月5日
许可协议