我有一些代码(实际上不是我的,但是SlickGrid库)创建了一个<style>
元素,将其插入到DOM中,然后立即尝试在document.styleSheets中找到新的样式表。采集。
在WebKit中,这有时会失败。我实际上并不知道情况如何,但这并不是一贯可重复的。我想我可以通过更改代码来解决它,所以在样式元素上的load
事件之前不会检查StyleSheet对象,如下所示:
$style = $("<style type='text/css' rel='stylesheet' />").appendTo($("head"));
var rules = ...;// code to create the text of the rules here
if ($style[0].styleSheet) { // IE
$style[0].styleSheet.cssText = rules.join(" ");
} else {
$style[0].appendChild(document.createTextNode(rules.join(" ")));
}
$style.bind('load', function() {
functionThatExpectsTheStylesheet();
});
和functionThatExpectsTheStylesheet尝试找到实际的样式表对象,如下所示:
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
if ((sheets[i].ownerNode || sheets[i].owningElement) == $style[0]) {
stylesheet = sheets[i];
break;
}
}
但有时甚至在那时,找不到样式表对象。
所以,我的问题是:
load
事件实际上不保证styleSheet对象可用吗?这是一个错误吗?答案 0 :(得分:6)
遗憾的是,动态加载CSS样式表仍然是一个充满浏览器怪癖的领域。在Webkit中,<style>
和<link>
元素在加载样式表时都会fire load
and error
events。但是,load
事件本身仅表示已加载样式表资源,而不一定是已将其添加到document.styleSheets
。
require-css RequireJS加载程序通过基于userAgent嗅探分支其加载机制来处理此问题(几乎不可能对功能进行检测<link>
标记是否会触发其{{1}事件正确)。特别是对于Webkit,检测采用load
来查找StyleSheet对象何时附加到setTimeout
document.styleSheets
因此,虽然var webkitLoadCheck = function(link, callback) {
setTimeout(function() {
for (var i = 0; i < document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
if (sheet.href == link.href)
return callback();
}
webkitLoadCheck(link, callback);
}, 10);
}
事件将在Webkit上触发,但为了能够访问相应的load
实例,它是不可靠的。
目前唯一正确支持样式表StyleSheet
事件的引擎是Firefox 18 +。
披露:我是require-css
的撰稿人参考文献:
答案 1 :(得分:0)
我认为load事件可能比css样式表更早触发。问题可能会发生在10次中,但仍然不是最佳做法和最干净的方式。
setTimeout肯定是一个很好的方法,因为可以保证你的脚本首先加载css。但是,由于只创建了样式表的标签,表示创建它的链接,因此需要首先下载css,所以无论你使用它们的方法是什么,都绝不能保证在加载事件之前加载你的css火灾。
要100%确定一切都按正确的顺序运行,通过AJAX进行同步文件读取,或者使用辅助函数进行异步AJAX调用,检查CSS是否准备就绪(这样你就不会冻结浏览器但仍然能够检查文件是否已加载)。另一种方法是链接样式表手册:首先设置样式表,然后是HTML文件标题中的代码。
我没有深入研究加载事件,但可能是DOMContentLoaded事件只在加载CSS时触发(对此问题的研究不足)
答案 2 :(得分:0)
我没有声称有解决方案,也没有对Webkit加载时序的解释,但我最近遇到了类似的问题,但是对于JS:我需要绝对确定在我包含其他之前加载了jQuery框架我自己的库,依赖于jQuery。
然后我注意到jQuery的load
事件在我预期时没有被触发。
对于它的价值,我在这里解决了我的问题:
var addedHead = window.document.createElement('link');
addedHead.async = true;
addedHead.onload = addedHead.onreadystatechange = function () {
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')
{
callback();
addedHead.onload = addedHead.onreadystatechange = null;
}
};
//And then append it to the head tag
你可以尝试一下!
答案 3 :(得分:0)
有同样的需要,使用样式规则的检测来检查样式表是否已加载。
// Load CSS dynamically. There's no way to determine when stylesheet has been loaded
// so we usingn hack - define `#my-css-loaded {position: absolute;}` rule in stylesheet
// and the `callback` will be called when it's loaded.
var loadCss = function(url, cssFileId, callback){
// CSS in IE can be added only with `createStyleSheet`.
if(document.createStyleSheet) document.createStyleSheet(url)
else $('<link rel="stylesheet" type="text/css" href="' + url + '" />').appendTo('head')
// There's no API to notify when styles will be loaded, using hack to
// determine if it's loaded or not.
var $testEl = $('<div id="' + cssFileId + '" style="display: none;"></div>').appendTo('body')
var checkIfStyleHasBeenLoaded = function(){
if($testEl.css('position') == 'absolute'){
$testEl.remove()
callback()
}else setTimeout(checkIfStyleHasBeenLoaded, 10)
}
setTimeout(checkIfStyleHasBeenLoaded, 0)
}