在Chrome上,添加样式表时不会更新document.styleSheets

时间:2015-04-05 18:13:39

标签: javascript css google-chrome

显然,Google Chrome中的属性document.styleSheets存在问题。添加新样式表后,不会更新该属性。 要重现该问题,只需运行以下代码:

    // Create the link element
    var element = document.createElement("link");
    element.setAttribute("rel", "stylesheet");
    element.setAttribute("type", "text/css");
    element.setAttribute("href", "external.css");

    // Add the link element
    console.log('Before add: ' + document.styleSheets.length);
    document.getElementsByTagName("head")[0].appendChild(link);
    console.log('After add: ' + document.styleSheets.length);

在FireFox中运行时,控制台将显示如下内容:

    Before add: 4
    After add: 5

在Chrome中运行时,控制台会显示如下内容:

    Before add: 4
    After add: 4

有趣的是,以下代码在两个浏览器上都能正常工作(返回相同的结果):

    console.log('Before add: ' + document.getElementsByTagName("head")[0].children);
    document.getElementsByTagName("head")[0].appendChild(link);
    console.log('After add: ' + document.getElementsByTagName("head")[0].children);

这是一个错误还是我做错了什么?

我在编写和测试以下函数时发现了这个问题,以便将CSS文件动态添加到网页中:

function requiresCSS( name ) { 
    var sheets = document.styleSheets; 
    for (var i = 0; i < sheets.length; i++) { 
        if (sheets[i].href && sheets[i].href.indexOf(name) !== -1) { 
            return; 
        } 
    }

    var link = document.createElement("link"); 
    link.rel = "stylesheet";
    link.type = "text/css"; 
    link.href = name; 
    document.getElementsByTagName("head")[0].appendChild(link); 
}    

尝试两次添加CSS时,该功能在Firefox上完美运行,但在Chrome上失败。

1 个答案:

答案 0 :(得分:5)

您正在添加外部文件,然后立即进行检查。如果您还没有看到它,这并不奇怪,HTTP请求可能仍然非常出色。如果您稍后再回来查看,一旦HTTP请求完成并解析并应用了样式,您就会在document.styleSheets中看到它。

根据HTML5 specification,您可以使用link元素上的load事件来获取资源加载时间的通知。所以:

element.addEventListener("load", function() {
    console.log('After add: ' + document.styleSheets.length);
}, false);
console.log('Before add: ' + document.styleSheets.length);
document.getElementsByTagName("head")[0].appendChild(link);

当然,加载和解析/应用可能不是同时发生的,所以如果您仍然看到差异,那么您可能需要setTimeout

element.addEventListener("load", function() {
    setTimeout(function() {
        console.log('After add: ' + document.styleSheets.length);
    }, 0);
}, false);
console.log('Before add: ' + document.styleSheets.length);
document.getElementsByTagName("head")[0].appendChild(link);

重新尝试避免添加样式表两次的函数,因为即使document.styleSheets中的条目不是元素元素也是可靠的,我只是寻找元素:

function requiresCSS( name ) { 
    // If we already have an element for this stylesheet, return
    if (document.querySelector('link[rel=stylesheet][href="' + name + '"]') {
        return;
    }

    // Add it
    var link = document.createElement("link"); link.rel = "stylesheet";
    link.type = "text/css"; link.href = name; 
    document.getElementsByTagName("head")[0].appendChild(link); 
}    

(您也可以使用querySelector查找head,它会更简洁。所有现代浏览器都支持querySelector / querySelectorAll,还有IE8。)