DOM实现运动模糊效果仅在开启开发者工具时生效,关闭后失效问题求助
问题根因
你的现象是Chromium内核浏览器(包括你使用的OperaGX)的定时器合并优化导致的:
- 未开启开发者工具时,浏览器会默认开启性能优化:所有小于4ms的
setTimeout会被强制延迟到4ms执行,且时间接近的定时器任务会被合并到同一个渲染帧批量执行。你设置的delayedPromiseArray[i].vel是0~29ms的极短延迟,这些位置更新任务最后几乎同时执行,拖影的位置差就消失了。 - 开启开发者工具时,浏览器为了保证调试时的时间精度,会默认关闭定时器合并优化,每个
setTimeout都会按照你设置的延迟独立触发,所以能看到正常的拖影效果。
另外你的实现逻辑本身也存在缺陷:mousemove事件触发频率远高于60帧,每次触发都会注册30个定时器,会产生大量冗余任务,进一步加剧定时器合并的问题。
修复方案
不要依赖setTimeout的时间差实现拖影,改为维护鼠标坐标的历史队列,在独立的requestAnimationFrame渲染循环中,让不同透明度的圆点分别跟随不同时间点的历史坐标,完全规避定时器优化的影响。
修复后的代码
JavaScript
window.addEventListener('load', function (e) { const SAMPLES = 30; // 拖影采样数 const MOTION_BLUR_STRENGTH = 2; // 拖影长度,可自行调整 let autoAlpha = 1 / SAMPLES; // 鼠标坐标历史队列,初始值为屏幕中心 let mouseHistory = new Array(SAMPLES).fill({x: window.innerWidth/2, y: window.innerHeight/2}); // 样式定义 let style = document.createElement('style'); style.innerHTML = ` *{ padding: 0; margin: 0; box-sizing: border-box; } html{ min-height: 100%; height: 100%; } .mouseInjectionWrapper{ inset: 0; position: fixed; width: 100vw; height: 100vh; background-color: transparent; } .boxdivmouseinjected{ border-radius: 50%; position: absolute; border: 2px solid red; width: 15px; height: 15px; background-color: #FFFFFF; transform: translate(-50%, -50%); } `; document.head.appendChild(style); let wboxdiv = document.createElement('div'); wboxdiv.classList.add('mouseInjectionWrapper'); wboxdiv = document.body.appendChild(wboxdiv); // 生成拖影圆点 let boxList = []; for (let i = 0; i < SAMPLES; i++) { let boxdiv = document.createElement('div'); boxdiv.classList.add('boxdivmouseinjected'); boxdiv.style.opacity = autoAlpha * (SAMPLES - i); wboxdiv.appendChild(boxdiv); boxList.push(boxdiv); } // 监听鼠标移动更新最新坐标 window.addEventListener('mousemove', function (e) { // 把最新坐标放到队列头部 mouseHistory.unshift({x: e.clientX, y: e.clientY}); // 队列长度保持和采样数一致,避免内存溢出 if(mouseHistory.length > SAMPLES) mouseHistory.pop(); }) // 独立渲染循环 function render() { // 每个圆点对应历史队列里的对应位置坐标,间隔越大拖影越长 boxList.forEach((box, index) => { const historyPos = mouseHistory[Math.min(index * MOTION_BLUR_STRENGTH, mouseHistory.length -1)]; box.style.left = `${historyPos.x}px`; box.style.top = `${historyPos.y}px`; }) requestAnimationFrame(render); } render(); });
HTML部分无需修改
验证说明
修复后的实现完全不依赖setTimeout,通过历史坐标队列直接控制拖影的位置差,不管是否开启开发者工具都能正常显示运动模糊效果,同时性能远高于原实现,不会产生大量冗余定时器任务。
内容的提问来源于stack exchange,提问作者Pedro Reinaldo
相关产品推荐
相关产品推荐

