MutationObserver和当前/计算的CSS样式

时间:2013-12-04 00:46:20

标签: javascript html css mutation-observers

我正在使用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内容。

实现此功能的最佳方法是什么?我想我正在进行一种改变式的变异,但我怀疑它是否存在。

1 个答案:

答案 0 :(得分:5)

这对我有用......

  1. 使用变异观察器来捕捉对样式属性的更改......

    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

  2. 使用变异观察器捕获新的stylelink元素,添加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]);
            }
        }
    };