javascript:在 LINK 上捕获加载事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2635814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:15:17  来源:igfitidea点击:

javascript: capturing load event on LINK

javascriptjavascript-events

提问by pgn

i'm trying to attach an event handler to the load event of a link tag, to execute some code after a stylesheet has loaded.

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

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)

i have tried onreadystatechange as well

我也试过 onreadystatechange

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

unfortunately neither approach results in an alert being triggered.. Furthermore, new_element.onload is null after registering a handler for the 'load' event with addEventListener.. is that normal?

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

thanks, andrew

谢谢,安德鲁

ps: i may not use any framework in solving this

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

采纳答案by Tobiasz Cudnik

For CSS stylesheets (not LINK elements in general) i'm using manual interval, by poking it's rules length. It works crossbrowser (AFAIT).

对于 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){}

In code above, the cssStylesheet is DOMElement.

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

回答by csuwldcat

Here's what is, in my opinion, a better solution for this issue that uses the IMG tag and its onerror event. This method will do the job without looping, doing contorted style observance, or loading files in iframes, etc. This solution fires correctly when the file is loads, and right away if the file is already cached (which is ironically better than how most DOM load events handle cached assets). Here's a post on my blog that explains the method - Back Alley Coder post- I just got tired of this not having a legit solution, enjoy!

在我看来,这是使用 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;
}

回答by Alex K.

Even if you add an inline:

即使您添加了内联:

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

It won't fire in FireFox as there isn'tan onloadevent for linkelements. (It will work in IE)

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

回答by Matt

All credit goes to Tobiasz up above, but here's a little expansion on what he said:

所有功劳都归功于上面的 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);
        }
}

You'd call it with something like (using jquery):

你会用类似的东西(使用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));

回答by matsko

The link.innerHTML, link.styleSheet and cssRules are all good approaches, but they do not work for stylesheets that belong to a domain outside of the origin domain (so cross-site stylesheet loading fails). This can be pretty unexpected when a subdomain vs a domain is used (www for example) or a static CNS is used. And its pretty annoying since elements have no same-origin restriction.

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

Here's a solution that that uses the onload method for browsers that support it (IE and Opera), but then uses a timed interval for browsers that do not and compares the ownerNode and owningElement nodes to check to see when the stylesheet has made its way into the DOM.

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

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

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

回答by Tyler Biscoe

This function has held up on all browsers as well as in both cross domain and same domain situations, also this handles the injection of javascripts as well as stylesheets.

此功能在所有浏览器以及跨域和同域情况下都支持,这也处理 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;
};

回答by Tom Roggero

Nice shot Matt. I've created this helper with your comment.

拍得不错马特。我已经根据您的评论创建了这个助手。

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);
    }
};

Usage:

用法:

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

回答by Serg Hospodarets

E.g. Android browser doesn't support "onload" / "onreadystatechange" events for element: http://pieisgood.org/test/script-link-events/
But it returns:

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

"onload" in link === true

So, my solution is to detect Android browser from userAgent and then wait for some special css rule in your stylesheet (e.g., reset for "body" margins).
If it's not Android browser and it supports "onload" event- we will use it:

因此,我的解决方案是从 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();
}

Demo: http://codepen.io/malyw/pen/AuCtH

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

回答by matpol

An href does not have a load event you need to apply your stuff as the page itself loads e.g.

href 没有加载事件,您需要在页面本身加载时应用您的内容,例如

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

}

use the function on this page: http://www.dustindiaz.com/top-ten-javascript/

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

to add the event the body element (in line would be )

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