link element onload

2019-01-08 16:32发布

Is there anyway to listen to the onload event for a <link> element?

F.ex:

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';

link.onload = link.onreadystatechange = function(e) {
    console.log(e);
};

This works for <script> elements, but not <link>. Is there another way? I just need to know when the styles in the external stylesheet has applied to the DOM.

Update:

Would it be an idea to inject a hidden <iframe>, add the <link> to the head and listen for the window.onload event in the iframe? It should trigger when the css is loaded, but it might not guarantee that it's loaded in the top window...

10条回答
放荡不羁爱自由
2楼-- · 2019-01-08 16:45
// this work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// if you want to use Promise in an non-es6 browser, add an ES6 poly-fill (or rewrite to use a callback)

let fetchStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.onload = resolve;
    link.href = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};
查看更多
相关推荐>>
3楼-- · 2019-01-08 16:46

This is kind of a hack, but if you can edit the CSS, you could add a special style (with no visible effect) that you can listen for using the technique in this post: http://www.west-wind.com/weblog/posts/478985.aspx

You would need an element in the page that has a class or an id that the CSS will affect. When your code detects that its style has changed, the CSS has been loaded.

A hack, as I said :)

查看更多
神经病院院长
4楼-- · 2019-01-08 16:46

The xLazyLoader plugin fails since the cssRules properties are hidden for stylesheets that belong to other domains (breaks the same origin policy). So what you have to do is compare the ownerNode and owningElements.

Here is a thorough explanation of what todo: http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/

查看更多
何必那么认真
5楼-- · 2019-01-08 16:49

The way I did it on Chrome (not tested on other browsers) is to load the CSS using an Image object and catching its onerror event. The thing is that browser does not know is this resource an image or not, so it will try fetching it anyway. However, since it is not an actual image it will trigger onerror handlers.

var css = new Image();
css.onerror = function() {
    // method body
}
// Set the url of the CSS. In link case, link.href
// This will make the browser try to fetch the resource.
css.src = url_of_the_css;

Note that if the resource has already been fetched, this fetch request will hit the cache.

查看更多
放荡不羁爱自由
6楼-- · 2019-01-08 16:51

This trick is borrowed from the xLazyLoader jQuery plugin:

var count = 0;

(function(){
  try {
    link.sheet.cssRules;
  } catch (e) {
    if(count++ < 100)
      cssTimeout = setTimeout(arguments.callee, 20);
    else
      console.log('load failed (FF)');
    return;
  };
  if(link.sheet.cssRules && link.sheet.cssRules.length == 0) // fail in chrome?
    console.log('load failed (Webkit)');
  else
    console.log('loaded');
})();

Tested and working locally in FF (3.6.3) and Chrome (linux - 6.0.408.1 dev)

Demo here (note that this won't work for cross-site css loading, as is done in the demo, under FF)

查看更多
Luminary・发光体
7楼-- · 2019-01-08 16:52

Since you didn't like my hack :) I looked around for some other way and found one by brothercake.

Basically, what is suggested is to get the CSS using AJAX to make the browser cache it and then treat the link load as instantaneous, since the CSS is cached. This will probably not work every single time (since some browsers may have cache turned off, for example), but almost always.

查看更多
登录 后发表回答