侧边栏壁纸
  • 累计撰写 635 篇文章
  • 累计收到 0 条评论

检测 DOM 结点插入

加速器之家
2024-08-24 / 0 评论 / 4 阅读 / 正在检测是否收录...

闲逛 Github 时碰见一个叫 SentinelJS 的库,声称能检测 DOM 结点的插入,顿时引起了好奇。因为以前无聊时也想过一下,没什么头绪,便不了了之。当时第一反应是该不会用轮询吧(比这粗暴的实现也不是没见过)。但看到 682 bytes (minified + gzipped) 大小时感觉一定又是用了什么奇淫怪巧,个人对这种东西很感兴趣(见另一篇《巧妙监测元素尺寸变化》),便顺便看了看源码,很短,但一看到 animation 时便拍大腿了!通过检测 animationstart 事件来检测插入,机智!

代码很短,就是维护了一个事件队列。核心在 onFnoffFn 上。后者同理,便主要看 onFn 的实现。

/**
* Add watcher.
* @param {array} cssSelectors - List of CSS selector strings
* @param {Function} callback - The callback function
*/
function onFn(cssSelectors, callback, extraAnimations) { if (!callback) return; // initialize animationstart event listener if (!isInitialized) init(); // listify argument cssSelectors = Array.isArray(cssSelectors) ? cssSelectors : [cssSelectors]; // add css rules and cache callbacks cssSelectors.map(function(selector) { var animId = selectorToAnimationMap[selector]; if (!animId) { // add new CSS listener var css, i; animId = 'sentinel-' + Math.random().toString(16).slice(2); // add keyframe rule css = '@keyframes ' + animId + '{from{transform:none;}to{transform:none;}}'; i = styleSheet.cssRules.length; styleSheet.insertRule(css, i); styleSheet.cssRules[i]._id = selector; // add selector animation rule css = selector + '{animation-duration:0.0001s;animation-name:' + animId; if (extraAnimations) css += ',' + extraAnimations; css += ';}'; i += 1; styleSheet.insertRule(css, i); styleSheet.cssRules[i]._id = selector; // add to map selectorToAnimationMap[selector] = animId; } // add to callbacks var x = animationCallbacks[animId] = animationCallbacks[animId] || []; x.push(callback); }); }

先生成一个随机的带前缀的 animId 来区分每个事件。

animId = 'sentinel-' + Math.random().toString(16).slice(2);

styleSheet 为一个事先挂载的