我正在使用 MutationObserver 来查找添加到网页的图像。由于许多图像是通过 CSS
background-image
属性显示的,因此除了查找 img
标签之外,我还检查当前/计算的 CSS 样式,例如...
var hasBackgroundImage = function(node) {
var nodeStyle = node.currentStyle || getComputedStyle(node, null);
return (
nodeStyle &&
nodeStyle.backgroundImage &&
nodeStyle.backgroundImage != "none"
);
};
但是,触发突变事件的节点与应用 CSS 规则之间似乎存在延迟,因此 在突变事件期间似乎没有
backgroundImage
,即使稍后某个时刻会有 。当代码在调试期间工作(使用断点)但在运行时不起作用时,我注意到了这一点。使用 setTimeout
延迟突变事件处理也有效,但可以肯定的是,延迟需要相当大,并且在不同页面之间会发生变化(我不确定何时保证应用 CSS 规则)。可能的原因可能只是 CSS 内容的延迟加载或注入。
实现此功能的最佳方法是什么?我想我正在追求风格改变突变,但我怀疑这是否存在。
这对我有用...
使用突变观察器捕获样式属性的更改...
var observer = new MutationObserver(parseMutations);
observer.observe(document, {
...
attributes: true,
attributeFilter: ["style"]
});
...
if (mutation.attributeName) //we'll assume it's "style"
parseNode(mutation.target); //check for style.backgroundImage and call filterNode()
这适用于
setAttribute("style", ...)
和 element.style.whatever = something
。使用突变观察器捕获新的
style
和 link
元素,添加 onload
事件并解析适用的节点...
var stylenodes = ["STYLE", "LINK"];
...
for (var i = 0; i < mutation.addedNodes.length; i++)
{
var node = mutation.addedNodes[i];
var nodeName = node.nodeName.toUpperCase();
if (stylenodes.indexOf(nodeName) !== -1)
node.addEventListener("load", styleLoaded);
...
//catch loading of stylenodes and parse all new rules
var currentLoadedStyles = [];
var styleLoaded = function() {
//check all styles and look for one that has just added some rules
for (var i = 0; i < document.styleSheets.length; ++i)
{
if (document.styleSheets[i].rules && document.styleSheets[i].rules.length > 0 && currentLoadedStyles.indexOf(document.styleSheets[i]) == -1)
{
currentLoadedStyles.push(document.styleSheets[i]);
parseNewStyle(document.styleSheets[i].rules);
}
}
};
//look for rules with background images and re-filter all nodes it applies to
var parseNewStyle = function(rules) {
for (var i = 0; i < rules.length; ++i)
{
//if any rule contains a background-image (could look for anything here really)
if (rules[i].style && rules[i].style.backgroundImage && rules[i].style.backgroundImage != "none")
{
//get all affected nodes and re-parse them
var nodes = document.querySelectorAll(rules[i].selectorText);
for (var j = 0; j < nodes.length; ++j)
filterNode(nodes[j]);
}
}
};
我使用 https://github.com/keithclark/CompulatedStyleObserver 来观察计算的样式“显示”并根据其值进行更改。这是代码:(在我的例子中,它是一个 Vue.js 项目)
setup(){
let observer = null;
const collapsableItemsOnNavbar = ref(null);
onMounted(() =>{
// This is to make sure that the Profile menu displays correctly between screen sizes
const callback = entries => {
entries.forEach(entry => {
console.log(`Property '${entry.property}' changed from '${entry.previousValue}' to '${entry.value}'`);
nextTick(() => {
let displayType = entry.value;
console.log(displayType);
if(displayType === 'none' || displayType === 'block'){
// We are in a small screen, don't display the profile picture
app.onNavbarCollapseChanged(true);
}
else{
// We are in a bigger screen, display the profile picture
app.onNavbarCollapseChanged(false);
}
});
});
}
observer = new ComputedStyleObserver(callback, ['display']);
observer.observe(collapsableItemsOnNavbar.value);
});
onBeforeUnmount(() =>{
observer.disconnect();
});
return {
collapsableItemsOnNavbar,
};
},
我创建了一个包
@bramus/style-observer
以允许您执行此操作。
通过NPM安装:
npm i @bramus/style-observer
并像这样使用它:
import CSSStyleObserver from '@bramus/style-observer'
const cssStyleObserver = new CSSStyleObserver(
/* Array of CSS Properties to observe */
['--variable1', '--variable2', 'display', 'border-width'],
/* This is called whenever there is a change in one of the observed properties */
(values) => {
console.log(values);
},
);
cssStyleObserver.attach(document.body);
该库不依赖于
requestAnimationFrame
,而是通过在观察到的属性上声明一个非常短的转换来工作。为了满足不通过插值设置动画的属性(例如自定义属性),它还依赖于相当新的 transition-behavior: allow-discrete
。这种方法在图书馆的公告帖子中有详细介绍:https://brm.us/style-observer