Подтвердить что ты не робот

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

спасибо, эндрю

ps: я не могу использовать какую-либо фреймворк в решении этого

4b9b3361

Ответ 1

Для таблиц стилей 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.

Ответ 2

Вот что, на мой взгляд, лучшее решение для этой проблемы, использующее тег IMG и его событие onerror. Этот метод выполнит задание без цикла, выполнив искаженное соответствие стиля или загрузив файлы в iframe и т.д. Это решение срабатывает корректно, когда файл загружается, и сразу же, если файл уже кэширован (что иронически лучше, чем большинство 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;
}

Ответ 3

Даже если вы добавите строку:

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

Он не будет срабатывать в FireFox, так как не является событием onload для link элементов. (Он будет работать в IE)

Ответ 4

Все кредиты идут на 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));

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

Эта функция задерживается во всех браузерах, а также в ситуациях с перекрестными доменами и в том же домене, также это обрабатывает инъекции 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;
};

Ответ 8

например. Android-браузер не поддерживает события "onload" / "onreadystatechange" для элемента: http://pieisgood.org/test/script-link-events/
Но он возвращает:

"onload" in link === true

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

Ответ 9

В href нет события загрузки, которое необходимо применить к вашему материалу, поскольку сама страница загружается, например.

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

}

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

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