javascript:在LINK上捕获加载事件

我试图将一个事件处理程序附加到链接标记的加载事件,以在样式表加载后执行一些代码。

new_element = document.createElement('link'); new_element.type = 'text/css'; new_element.rel = 'stylesheet'; new_element.href = 'http://domain.tld/file.css'; new_element.addEventListener('load', function() { alert('foo'); }, false); document.getElementsByTagName('head')[0].appendChild(new_element) 

我也试过onreadystatechange

 new_element.onreadystatechange = function() { alert('foo'); } 

不幸的是,这两种方法都不会导致警报被触发。此外,new_element.onload在为addEventListener注册'load'事件的处理程序之后为空。是正常的吗?

谢谢,安德鲁

ps:我可能不会使用任何框架来解决这个问题

对于CSS样式表(通常不是LINK元素),我使用手动间隔,通过戳它的规则长度。 它运作交叉浏览器(AFAIT)。

 try { if ( cssStylesheet.sheet && cssStylesheet.sheet.cssRules.length > 0 ) cssLoaded = 1; else if ( cssStylesheet.styleSheet && cssStylesheet.styleSheet.cssText.length > 0 ) cssLoaded = 1; else if ( cssStylesheet.innerHTML && cssStylesheet.innerHTML.length > 0 ) cssLoaded = 1; } catch(ex){} 

在上面的代码中,cssStylesheet是DOMElement。

在我看来,这是一个更好的解决scheme,这个问题使用IMG标签和它的onerror事件。 这个方法可以在没有循环的情况下执行这个工作,执行扭曲的样式遵守,或者在iframe中加载文件等等。这个解决scheme在文件被加载的时候正确地激发,并且如果文件已经被caching了(这比大多数DOM加载事件处理caching的资产)。 这里是我的博客上的一篇文章,解释了这种方法 – 后巷编码器后 – 我只是厌倦了这个没有一个合法的解决scheme,享受!

 var loadCSS = function(url, callback){ var link = document.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = url; document.getElementsByTagName('head')[0].appendChild(link); var img = document.createElement('img'); img.onerror = function(){ if(callback) callback(link); } img.src = url; } 

即使你添加一个内联:

 <link rel="stylesheet" type="text/css" href="foo.css" onload="alert('xxx')"/> 

它不会在FireFox中触发,因为link元素没有 onload事件。 (它将在IE中工作)

上面所有的功劳都归托比亚斯所有,但是他所说的话有点扩展:

 function _cssIsLoaded(cssStylesheet) { var cssLoaded = 0; try { if ( cssStylesheet.sheet && cssStylesheet.sheet.cssRules.length > 0 ) cssLoaded = 1; else if ( cssStylesheet.styleSheet && cssStylesheet.styleSheet.cssText.length > 0 ) cssLoaded = 1; else if ( cssStylesheet.innerHTML && cssStylesheet.innerHTML.length > 0 ) cssLoaded = 1; } catch(ex){ } if(cssLoaded) { // your css is loaded! Do work! // I'd recommend having listeners subscribe to cssLoaded event, // and then here you can emit the event (ie. EventManager.emit('cssLoaded'); } else { // I'm using underscore library, but setTimeout would work too // You basically just need to call the function again in say, 50 ms _.delay(_.bind(this._cssIsLoaded, this), 50, cssStylesheet); } } 

你会用类似的东西(使用jquery)来调用它:

 var link = $("<link>"); link.attr({ type: 'text/css', rel: 'stylesheet', href: sheet }); $("head").append(link); // link.get(0), because you want the actual element, not jQuery-wrapped element self._cssIsLoaded(link.get(0)); 

link.innerHTML,link.styleSheet和cssRules都是很好的方法,但是它们不适用于属于原始域之外的域的样式表(所以跨站点样式表加载失败)。 当使用子域名与域名(例如www)或使用静态CNS时,这可能是相当意想不到的。 因为元素没有同源限制,所以它很烦人。

这是一个解决scheme,它使用支持它的浏览器的onload方法(IE和Opera),然后为浏览器使用定时间隔,然后比较ownerNode和owningElement节点,以检查样式表是否进入DOM。

http://www.yearofmoo.com/2011/03/cross-browser-stylesheet-preloading.html

尼斯开枪马特。 我已经用你的评论创build了这个帮手。

 var CSSload = function(link, callback) { var cssLoaded = false; try{ if ( link.sheet && link.sheet.cssRules.length > 0 ){ cssLoaded = true; }else if ( link.styleSheet && link.styleSheet.cssText.length > 0 ){ cssLoaded = true; }else if ( link.innerHTML && link.innerHTML.length > 0 ){ cssLoaded = true; } } catch(ex){ } if ( cssLoaded ){ callback(); }else{ setTimeout(function(){ CSSload(link); }, 100); } }; 

用法:

 var $link = $('<link rel="stylesheet" media="screen" href="file.css"/>'); $('head').append($link); CSSload($link.get(0), function(){ // do something onLoad }); 

这个function在所有的浏览器上以及在跨域和同域的情况下都是成立的,同时也处理javascript和样式表的注入。

 function loadScript(src, type, callback_fn) { var loaded = false, scrpt, img; if(type === 'script') { scrpt = document.createElement('script'); scrpt.setAttribute('type', 'text/javascript') scrpt.setAttribute('src', src); } else if(type === 'css') { scrpt = document.createElement('link') scrpt.setAttribute('rel', 'stylesheet') scrpt.setAttribute('type', 'text/css') scrpt.setAttribute('href', src); } document.getElementsByTagName('head')[0].appendChild(scrpt); scrpt.onreadystatechange = function(){ if (this.readyState === 'complete' || this.readyState === 'loaded') { if(loaded === false) { callback_fn(); } loaded = true; } }; scrpt.onload = function() { if(loaded === false) { callback_fn(); } loaded = true; }; img = document.createElement('img'); img.onerror = function(){ if(loaded === false) { callback_fn(); } loaded = true; } img.src = src; }; 

例如,Android浏览器不支持元素的“onload”/“onreadystatechange”事件: http : //pieisgood.org/test/script-link-events/
但它返回:

 "onload" in link === true 

所以,我的解决scheme是从userAgent中检测Android浏览器,然后在样式表中等待一些特殊的css规则(例如重置“body”边距)。
如果它不是Android浏览器,并支持“onload”事件,我们将使用它:

 var userAgent = navigator.userAgent, iChromeBrowser = /CriOS|Chrome/.test(userAgent), isAndroidBrowser = /Mozilla\/5.0/.test(userAgent) && /Android/.test(userAgent) && /AppleWebKit/.test(userAgent) && !iChromeBrowser; addCssLink('PATH/NAME.css', function(){ console.log('css is loaded'); }); function addCssLink(href, onload) { var css = document.createElement("link"); css.setAttribute("rel", "stylesheet"); css.setAttribute("type", "text/css"); css.setAttribute("href", href); document.head.appendChild(css); if (onload) { if (isAndroidBrowser || !("onload" in css)) { waitForCss({ success: onload }); } else { css.onload = onload; } } } // We will check for css reset for "body" element- if success-> than css is loaded function waitForCss(params) { var maxWaitTime = 1000, stepTime = 50, alreadyWaitedTime = 0; function nextStep() { var startTime = +new Date(), endTime; setTimeout(function () { endTime = +new Date(); alreadyWaitedTime += (endTime - startTime); if (alreadyWaitedTime >= maxWaitTime) { params.fail && params.fail(); } else { // check for style- if no- revoke timer if (window.getComputedStyle(document.body).marginTop === '0px') { params.success(); } else { nextStep(); } } }, stepTime); } nextStep(); } 

演示: http : //codepen.io/malyw/pen/AuCtH

一个href没有负载事件,你需要应用你的东西,因为页面本身加载,例如

 window.onload = function(){ //code here } 

使用此页面上的function: http : //www.dustindiaz.com/top-ten-javascript/

添加事件body元素(在行中)