- uselnterval & useTimeout
- ref 获取 DOM
- withDefaults 设置 props 默认值
- <style> 使用 <script setup> 里的 JS 变量
- v-html渲染html模板
- tansform: scale 实现小于 1px 的边线
- ScrollBar 轮播组件的实现原理
需求分析
1.使用 defineProps
函数和 withDefaults
函数
- 你使用
defineProps
函数和withDefaults
函数来定义和设置默认值。defineProps<IProps>()
创建了一个IProps
类型的 props 对象,withDefaults
函数设置了intervalTime
、transitionTime
和height
的默认值
interface IProps {
intervalTime?: number
transitionTime?: number
height?: number
data: IScrollBarInfo[]
}
const props = withDefaults(defineProps<IProps>(), {
intervalTime: 3000,
transitionTime: 1000,
height: 40
})
二.自定义hooks-useCountDown实现倒计时逻辑
- 使用 requestAnimationFrame(或 setTimeout) 计时
- useCountDown 的设计
- 性能优化:毫秒级/非毫秒级更新
01为什么要使用 requestAnimationFrame?
-
与浏览器的刷新率同步:
requestAnimationFrame
会将动画函数与浏览器的刷新率同步。这意味着它会在每次屏幕重绘之前执行一次,通常是每秒60次(60Hz)。这有助于创建平滑的动画效果,因为它避免了动画帧和屏幕刷新之间的不一致。
-
性能优化:
- 浏览器可以对使用
requestAnimationFrame
的动画进行优化,比如在页面未激活或标签页不可见时减少或暂停动画,从而降低能耗和提高性能。
- 浏览器可以对使用
-
减少界面重排和重绘:
- 由于
requestAnimationFrame
是与浏览器的绘制过程同步的,它可以减少不必要的DOM操作和界面重绘,从而提高性能。
- 由于
02为什么 setlnterval/setTimeout 不准?
-
1时间延迟不精确:
setTimeout
和setInterval
指定的是最小延迟时间,并不保证精确执行。实际调用的时间可能会由于浏览器的任务调度或其他正在运行的脚本而延迟。
-
2不与浏览器的刷新率同步:
- 这两种方法不考虑浏览器的绘制过程。因此,使用它们创建的动画可能与浏览器的帧率不同步,导致动画不流畅或出现“跳帧”现象。
-
3效率问题:
- 在快速或高性能的动画中,
setInterval
和setTimeout
可能导致性能问题,因为它们不能智能地调整动画帧率或在页面不可见时暂停动画。
- 在快速或高性能的动画中,
2useCountDown需求分析
- start 方法:开始计时
- pause 方法:暂停计时
- reset 方法:重置时间
- current 变量:当前时间
- 大量减少页面渲染的事件
- 性能优化:是否需要毫秒级的计时
- 当前剩余时间 currentRemain 是否与remain 为同一秒
- 具体做法
03性能优化:毫秒级/非毫秒级更新是怎么做的
在提供的 useCountDown
钩子代码中,性能优化主要体现在根据用户需求选择毫秒级或非毫秒级更新。这是通过两种不同的定时循环函数 microTick
和 macroTick
来实现的。让我们来看看这两个函数是如何根据不同的需求进行优化的:
1. 毫秒级更新(microTick
)
在毫秒级更新中,倒计时需要在每一帧都进行更新。这种方式在显示毫秒数时非常有用,因为它可以提供非常平滑和精确的倒计时显示。
microTick
函数会在每次浏览器重绘之前执行一次,即每一帧都会更新。- 通过
requestAnimationFrame
(rAF
)递归调用自己,它确保倒计时的更新与浏览器的帧率同步,这对于渲染流畅的动画非常重要。 - 这种方法在性能上是有效的,因为
requestAnimationFrame
通常是浏览器优化动画和重绘的首选方式。
2. 非毫秒级更新(macroTick
)
非毫秒级更新适用于不需要显示毫秒数的场景。在这种模式下,更新频率降低,只有当剩余时间的秒数发生变化时才进行更新。
macroTick
函数使用requestAnimationFrame
递归调用自己,但不是在每一帧都更新倒计时。- 它检查当前剩余时间与上一次剩余时间是否处于同一秒。如果是同一秒,则不更新;只有当进入下一秒时才更新,这通过
isSameSecond
函数检查实现。 - 这种方法减少了更新的频率,降低了对性能的影响,特别是当倒计时组件不需要展示毫秒数时。
总结
性能优化的关键在于根据需求选择合适的更新频率。毫秒级更新提供了更高的精确度和平滑度,适合动态和高精度的显示需求。非毫秒级更新则在不需要高频率更新时降低了性能消耗,提高了效率。通过这种方式,useCountDown
钩子能够根据具体的使用场景灵活地调整其性能和精确度
04useCountDown
倒计时钩子的逻辑
基于几个关键目标:提供一个灵活的倒计时功能,支持毫秒级更新,能够处理倒计时的开始、暂停、重置,以及在倒计时过程中触发特定的回调。以下是这段代码的核心逻辑:
1. 定义数据结构和类型
- 类型定义:
CurrentTime
和UseCountDownOptions
类型用于定义倒计时的数据结构和钩子的配置选项。 - 时间单位常量:定义了秒、分钟、小时和天的毫秒值,以便于后续的时间计算。
2. 辅助函数
parseTime
函数:将给定的时间(毫秒)解析为天、小时、分钟、秒和毫秒的组合。isSameSecond
函数:判断两个时间值是否处于同一秒内,用于非毫秒级更新的优化。
3. 主要逻辑
- 初始化状态:使用 Vue 的
ref
创建响应式变量remain
来存储剩余时间,以及使用computed
创建计算属性current
来实时解析剩余时间的结构。 - 暂停和重置:
pause
函数用于停止倒计时,reset
函数用于重置倒计时。 - 倒计时更新:
microTick
和macroTick
函数使用requestAnimationFrame
来递归地更新倒计时。microTick
用于毫秒级更新,而macroTick
用于秒级更新。 - 开始倒计时:
start
函数设置了倒计时的结束时间,并开始了更新循环。
4. 回调和剩余时间更新
- 更新剩余时间:
setRemain
函数更新remain
的值,并在每次更新时调用onChange
回调(如果提供)。 - 倒计时结束处理:当剩余时间为0时,
setRemain
函数调用onFinish
回调(如果提供)并停止倒计时。
5. 返回接口
- 最后,钩子返回一个包含
start
、pause
、reset
和current
的对象,使得这些功能可以在组件中被访问和使用。
总体思考逻辑
- 灵活性:钩子需要能够处理不同的倒计时需求,包括毫秒级的精确度。
- 性能:使用
requestAnimationFrame
优化动画性能,确保倒计时更新平滑且高效。 - 可用性:提供开始、暂停和重置功能,使得倒计时可以在各种情景下灵活使用。
- 响应性:确保倒计时的当前状态可以响应式地被Vue组件使用。
- 事件驱动:在关键事件(如每次更新和倒计时完成)时提供回调函数的触发。