Skip to content

Instantly share code, notes, and snippets.

@weger
Created December 22, 2014 08:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weger/e01d0bcf3fe3c059f891 to your computer and use it in GitHub Desktop.
Save weger/e01d0bcf3fe3c059f891 to your computer and use it in GitHub Desktop.
动态加载css,监听onload事件
/*
WebKit:
- linkNode.sheet 在 css 文件下载完成并解析好后才有值,之前为 undefined
- linkNode.sheet.cssRules 同域时返回 CSSRuleList, 跨域时返回 null
- WebKit >= 535.23 后支持 onload / onerror
Firefox:
- linkNode.sheet 在 css 插入 DOM 中后立刻有值,插入前为 undefined
- linkNode.sheet.cssRules 在文件还未下好时,抛出 NS_ERROR_DOM_INVALID_ACCESS_ERR
在文件下载并解析好后,
同域时返回 cssRuleList
跨域时抛出 NS_ERROR_DOM_SECURITY_ERR
- Firefox >= 9.0 后支持 onload / onerror
IE / Opera:
- linkNode.sheet 和 cssRules 在 css 插入 DOM 后都立刻可访问,cssRules 为 []
- 当文件下载完成时,cssRules 为 cssRuleList
- Opera 只在成功时触发 onload,失败时不会触发 onerror
- IE 下,无论成功失败,都会触发 onload,不会触发 onerror,中间会触发 onreadystatechange
- 期待 IE 和 Opera 的后续版本能正确支持 onerror
https://bugs.dojotoolkit.org/attachment/ticket/5402/requireCss.js
*/
dojo.provide("dojo.requireCss");
(function(){
var cssCounter = 0;
var cssInFlight = {};
var cssInFlightIntvl = null;
var cssStartTime = 0;
var idPrefix = dojo._scopeName + "RequireCss";
var _watchCssInFlight = function(){
//summary: watches to make sure all css files have loaded.
var stillWaiting = false;
for(var param in cssInFlight){
//Protect against bad JS modifying Object.prototype
if(typeof param == "string" && param.indexOf(idPrefix) == 0){
console.debug(cssInFlight[param].sheet);
if((dojo.isMoz || dojo.isSafari) && cssInFlight[param].sheet.cssRules){
//Since moz and safari do not work with onload callbacks on the link
//tag, see if the sheet and sheet.cssRules exist. If so, then assume
//the css file has be loaded.
delete cssInFlight[param];
}else{
stillWaiting = true;
}
}
}
if(stillWaiting){
//Make sure we have not reached the timeout stage.
var waitInterval = (dojo.config.cssWaitSeconds || 15) * 1000;
if((cssStartTime + waitInterval) < (new Date()).getTime()){
var err = "Timed out waiting for css files: ";
for(param in cssInFlight){
err += cssInFlight[param].href + " ";
}
throw err;
}
}else{
//All loaded. Clean up.
console.debug("all done");
clearInterval(cssInFlightIntvl);
cssInFlightIntvl = null;
}
}
dojo.requireCss = function(/*String*/resourceName){
//summary: Converts the resource name ("some.thing") to a CSS URL
//(http://some.domain.com/path/to/some/thing.css), then adds the CSS file
//to the page. Full urls can be passed in (instead of a "some.thing" resourceName.
//It also registers this CSS file with the dojo loader. This
//means that if you do a dojo.addOnLoad() callback after calling this function,
//the addOnLoad callback will not be fired until the CSS file has loaded.
//Note that style sheets may be evaluated in a different order than the order
//they appear in the DOM. If you want precise ordering of style rules, make
//one call to this function, then in a dojo.addOnLoad() callback, load the other,
//and repeat this call structure until you load all the stylesheets.
//Example:
// dojo.requireCss("some.thing");
// dojo.requireCss("http://some.domain.com/path/to/some/thing.css");
//Translate resource name to a file path
var path = resourceName;
if(path.indexOf("/") == -1){
path = dojo._getModuleSymbols(resourceName).join("/") + '.css';
path = ((path.charAt(0) == '/' || path.match(/^\w+:/)) ? "" : dojo.baseUrl) + path;
}
if(dojo.config.cacheBust){
path += (path.indexOf("?") == -1 ? "?" : "&") + String(dojo.config.cacheBust).replace(/\W+/g,"");
}
//Create the link node
var link = dojo.doc.createElement("link");
link.id = idPrefix + (cssCounter++);
link.type = "text/css";
link.rel = "stylesheet";
link.href = path;
cssInFlight[link.id] = link;
console.debug(link.id + " created");
//Set up loader hooks.
//TODO
//Register the onload trigger, if supported.
if(!(dojo.isMoz || dojo.isSafari)){
//IE and Opera, which support onload. A not test is used in the above if
//since for moz and safari, those are the only ones that are tested to have
//the sheet property that we will test in the inflight
//watch, so want to match that test with the one used here.
link.onload = function(){
console.debug(link.id + " loaded");
delete cssInFlight[link.id];
//Try to help break circular memory leaks.
link.onload = null;
}
}
//Attach the node to document.
if(!this.headElement){
this._headElement = document.getElementsByTagName("head")[0];
//Head element may not exist, particularly in html
//html 4 or tag soup cases where the page does not
//have a head tag in it. Use html element, since that will exist.
//Seems to be an issue mostly with Opera 9 and to lesser extent Safari 2
if(!this._headElement){
this._headElement = document.getElementsByTagName("html")[0];
}
}
console.debug(link.id + " adding to head");
this._headElement.appendChild(link);
//Start the inflight watch.
cssStartTime = (new Date()).getTime();
if(!cssInFlightIntvl){
cssInFlightIntvl = setInterval(_watchCssInFlight, 100);
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment