起源
在Google I/O 2023大会上,主持人在介绍GMail的AI功能时,使用了一段如下的打字机动画,下面就从这段动画入手,从头至尾解析如何去实现它。
解析
动画从头至尾分为三个部分:
- 打字机打字光标依次位移
- 光标移动至指定位置
- 光标移动至指定位置并进行划词
转换为数学语言,则是:
- 光标按字进行瞬移
- 光标移动到指定字符之间
- 光标移动到指定字符之间,并留下移动的背景色
步骤解析并进行数据建模
该问题主要涉及以下几个数据模型
- 单个字符
- 光标位置
- 光标位置的浏览器坐标
模型解析
- 字符位置
以ABC
字符串为例,进行插空定位0A1B2C3D
,但是这种模式在换行时会出现不知道留在上一行末尾还是下一行的头部的问题,因此除去数字定位,也需支持字符的前后标识位的能力
export type AnimateNumber =
| number // 数字模式
| ((str: string) => number) // 函数生成模式
| { isAfter: boolean, value: number } // 字符前后定位模式
| ((str: string) => { isAfter: boolean, value: number }) // 字符前后定位函数生成模式
- 动画钩子
为方面在动画前后插入执行操作,使用前后钩子来定义
export type AnimateHook =
| (() => Promise<void>) // 异步钩子
| Array<() => Promise<void>> // 异步多个钩子
| {
isParallel?: boolean
hooks: Array<() => Promise<void>>
} // 异步多个并行钩子
- 动画步骤
export type AnimateStep = {
preHook?: AnimateHook
afterHook?: AnimateHook
} & (
| {
type: 'typing',
start?: AnimateNumber
end?: AnimateNumber,
}
| {
type: 'move',
start?: AnimateNumber
end?: AnimateNumber
}
| {
type: 'choose',
start?: AnimateNumber
end?: AnimateNumber
}
)
代码实现解析
- 打字机效果
该效果下有一个特点,所有的光标均在最后,因此直接使用行内块的排版模式即可实现,定时增加文字即可
<span>Jay</span>
<span class="光标"></span>
-
移动效果
该模式直接使用定位,解析出每个字符所在位置即可 -
背景效果
该模式在上一步基础上增加一个背景渲染即可
小疑问解答
Q:如何获取到具体字符的坐标呢
A:将单个字符拆分,获取到每个元素的具体位置即可
Q:为什么不直接根据字符数量计算呢?
A:实际字体分为等宽字体、非等宽字体,在非等宽字体中,每个字符的宽度不一致,无法直接测算出实际占用宽度和高度。
实际效果及代码
其他问题
该代码为简易实现版本,未处理移动跨行的场景,可以自行研究进行增强。
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END