javascript: захват события загрузки ПО ССЫЛКЕ

Я пытаюсь прикрепить обработчик событий к событию load тега 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 имеет значение null после регистрации обработчика для события "load" с помощью addEventListener.. это нормально?

спасибо, Эндрю!--3-->

ps: Я не могу использовать рамки в решении этого

9 ответов


для таблиц стилей CSS (не элементов ссылок вообще) я использую ручной интервал, тыча его длину правил. Работает кроссбраузер (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.


вот что, на мой взгляд, является лучшим решением для этой проблемы, которая использует тег IMG и его событие onerror. Этот метод будет выполнять работу без цикла, соблюдения искаженного стиля или загрузки файлов в iframes и т. д. Это решение срабатывает правильно При загрузке файла и сразу же, если файл уже кэширован (что по иронии судьбы лучше, чем то, как большинство событий загрузки DOM обрабатывают кэшированные активы). Вот сообщение в моем блоге, которое объясняет метод -Переулок, Верстальщик пост - Я просто устал от этого, не имея законных решений, наслаждайтесь!

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

даже если вы добавляете inline:

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

Он не будет работать в FireFox, как там не an onload событие link элементы. (Это будет работать в 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));

ссылка.innerHTML будет, ссылке.таблицы стилей и cssRules-все хорошие подходы, но они не работают для таблиц стилей, принадлежащих домену за пределами исходного домена (поэтому загрузка межсайтовой таблицы стилей завершается неудачно). Это может быть довольно неожиданно, когда используется поддомен против домена (например, www) или используется статический CNS. И это довольно раздражает, так как элементы не имеют ограничений одного и того же происхождения.

вот решение, которое использует метод onload для браузеров, поддерживающих его (IE и Opera), но затем использует временной интервал для браузеров, которые этого не делают, и сравнивает узлы ownerNode и owningElement, чтобы проверить, когда таблица стилей пробралась в DOM.

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


хороший выстрел Мэтта. Я создал этого помощника с вашим комментарием.

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

эта функция задержалась во всех браузерах, а также в междоменных и одинаковых ситуациях домена, также это обрабатывает инъекции javascripts, а также таблиц стилей.

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

Итак, мое решение-обнаружить браузер Android от userAgent, а затем дождаться специального правила css в вашей таблице стилей (например, сброс для полей "тело").
Если это не браузер 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 нет события load, которое вам нужно применить, поскольку загружается сама страница, например

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

}

используйте функцию на этой странице:http://www.dustindiaz.com/top-ten-javascript/

чтобы добавить событие, элемент body (в строке будет)