捕获 LINK 上的加载事件

IT技术 javascript dom-events
2021-02-22 04:00:24

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

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在使用 注册load事件处理程序后为空addEventListener这是正常的吗?

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

6个回答

在我看来,这是使用 IMG 标记及其 onerror 事件的此问题的更好解决方案。此方法将完成工作而无需循环、执行扭曲的样式观察或在 iframe 中加载文件等。此解决方案在加载文件时正确触发,如果文件已被缓存(具有讽刺意味的是,这比大多数 DOM加载事件处理缓存的资产)。这是我博客上的一篇解释该方法的帖子- Back Alley Coder 帖子- 我只是厌倦了没有合法的解决方案,享受吧!

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;
}
这在 2011 年的 WebKit 目标上很奇怪。Bravo。
2021-04-18 04:00:24
当我尝试在 Mac 上的 Safari 中似乎不起作用时?(不过在 Chrome 和 FF 上很好)。还没有在 Windows 下的 Safari 上尝试过。
2021-04-29 04:00:24
我相信这是因为我将 img 元素附加到 HTML 元素而不是 body 元素。它现在在 Safari 中对我有用。
2021-05-11 04:00:24
IE 和 Opera 不需要这种方法,它们现在已经支持链接标签加载了一段时间。只需在基于 Gecko 和 Webkit 的浏览器中使用它。我正在扩充 MooTools More 的官方 Asset 方法,以便在链接元素不支持 onload 时智能地使用它,应该在我们即将发布的 MooTools 版本之一中。
2021-05-14 04:00:24
对我来说似乎非常好......这在浏览器中的支持程度如何?
2021-05-17 04:00:24

对于 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。

太棒了 Tobiasz!谢谢!我花了一点时间才明白您在说什么,所以对于像我这样可能有点困惑的人,请查看我的答案。
2021-05-04 04:00:24
这很好,除非您加载 css 跨域。如果你的 CSS 是在 CDN 上什么的,由于跨域限制,cssRules 是不可用的。另请参阅phpied.com/when-is-a-stylesheet-really-loaded
2021-05-08 04:00:24

即使您添加了内联:

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

它不会在Firefox火,因为没有一个onload事件link的元素。(它将在 IE 中工作)

从 Firefox 9 开始,支持链接标签 onload 和 onerror 事件。唯一未能提供这些关键事件的浏览器是 Google Chrome 和 Apple Safari。
2021-04-22 04:00:24
Chrome/Safari<link>从那时起就实现了 onload/onerror IE 没有onerror根据这个很棒的兼容性表来实现:pie.gd/test/script-link-events
2021-05-09 04:00:24

所有功劳都归功于上面的 Tobiasz,但这里有一些关于他所说的话的扩展:

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));
与上述 Tobiasz 的回答相同的限制,这不适用于 CDN 左右的跨域样式表。
2021-04-30 04:00:24

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

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

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

链接是 404,但可以通过 wayback 获得:wayback.archive.org/web/20160809031346/http : //www.yearofmoo.com/...
2021-04-22 04:00:24