forked from liweijie/education
防抖优化
This commit is contained in:
@@ -51,26 +51,33 @@ export function initAdaptive(designWidth = DEFAULT_DESIGN_WIDTH) {
|
||||
|
||||
const useZoom = isZoomSupported()
|
||||
|
||||
// 首次:渲染前同步应用一次,避免首帧闪烁
|
||||
apply()
|
||||
window.addEventListener('resize', onResize)
|
||||
// 从后台标签切回来时,若期间窗口尺寸变化(因 hidden 被跳过)需补算一次
|
||||
document.addEventListener('visibilitychange', onVisibilityChange)
|
||||
// rAF 帧对齐节流:把同一帧内多次 resize 合并为一次
|
||||
let rafId = null
|
||||
// 真实写入节流 + 尾随兜底:拖拽/设备模拟期间 resize 高频触发,
|
||||
// 若每帧都写 html.zoom 会强制整页重排+重绘导致卡顿,因此限制真实写入频率
|
||||
let lastAppliedScale = -1
|
||||
let lastWriteAt = 0
|
||||
let trailingTimer = null
|
||||
const WRITE_MIN_INTERVAL = 100 // ms
|
||||
|
||||
/**
|
||||
* 真正的缩放计算与写入。
|
||||
* 比例基于 window.innerWidth(窗宽),它不受页面自身 zoom 缩放影响,
|
||||
* 可避免因滚动条宽度变化造成的“缩放-比例”联动回摆。
|
||||
*/
|
||||
function apply() {
|
||||
function computeScale() {
|
||||
const root = document.documentElement
|
||||
const width = window.innerWidth || (root && root.clientWidth) || designWidth
|
||||
const ratio = width / designWidth
|
||||
// 收敛到 [MIN_SCALE, MAX_SCALE],规避极端宽高的异常比例
|
||||
return Math.min(MAX_SCALE, Math.max(MIN_SCALE, ratio))
|
||||
}
|
||||
|
||||
function writeScale(scale) {
|
||||
const root = document.documentElement
|
||||
if (!root) {
|
||||
return
|
||||
}
|
||||
const width = window.innerWidth || root.clientWidth || designWidth
|
||||
const ratio = width / designWidth
|
||||
// 收敛到 [MIN_SCALE, MAX_SCALE],规避极端宽高的异常比例
|
||||
const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, ratio))
|
||||
// 值未变化:跳过,避免冗余的样式失效/整页重排
|
||||
if (Math.abs(scale - lastAppliedScale) < 1e-4) {
|
||||
return
|
||||
}
|
||||
lastAppliedScale = scale
|
||||
|
||||
if (scale === 1) {
|
||||
clearScale(root)
|
||||
@@ -105,8 +112,11 @@ export function initAdaptive(designWidth = DEFAULT_DESIGN_WIDTH) {
|
||||
}
|
||||
}
|
||||
|
||||
// rAF 帧对齐节流:把同一帧内多次 resize 合并为一次应用,实时且顺滑
|
||||
let rafId = null
|
||||
/** 立即计算并写入一次(带值变化守卫) */
|
||||
function applyNow() {
|
||||
lastWriteAt = Date.now()
|
||||
writeScale(computeScale())
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
if (document.hidden) {
|
||||
@@ -117,15 +127,35 @@ export function initAdaptive(designWidth = DEFAULT_DESIGN_WIDTH) {
|
||||
}
|
||||
rafId = window.requestAnimationFrame(() => {
|
||||
rafId = null
|
||||
if (!document.hidden) {
|
||||
apply()
|
||||
if (document.hidden) {
|
||||
return
|
||||
}
|
||||
const now = Date.now()
|
||||
if (trailingTimer) {
|
||||
clearTimeout(trailingTimer)
|
||||
}
|
||||
// 距上次真实写入已超过阈值才立即写入,其余情况靠尾随兜底,避免满帧整页重排
|
||||
if (now - lastWriteAt >= WRITE_MIN_INTERVAL) {
|
||||
applyNow()
|
||||
}
|
||||
// 尾随:拖拽/改变尺寸停下后,确保落到最终窗口尺寸
|
||||
trailingTimer = setTimeout(applyNow, WRITE_MIN_INTERVAL)
|
||||
})
|
||||
}
|
||||
|
||||
function onVisibilityChange() {
|
||||
if (!document.hidden) {
|
||||
apply()
|
||||
// 从后台切回时补算一次
|
||||
if (trailingTimer) {
|
||||
clearTimeout(trailingTimer)
|
||||
}
|
||||
applyNow()
|
||||
}
|
||||
}
|
||||
|
||||
// 首次:渲染前同步应用一次,避免首帧闪烁
|
||||
applyNow()
|
||||
window.addEventListener('resize', onResize)
|
||||
// 从后台标签切回来时,若期间窗口尺寸变化(因 hidden 被跳过)需补算一次
|
||||
document.addEventListener('visibilitychange', onVisibilityChange)
|
||||
}
|
||||
Reference in New Issue
Block a user