JavaScript: захват события загрузки по ссылке - PullRequest
13 голосов
/ 14 апреля 2010

Я пытаюсь прикрепить обработчик события к событию загрузки тега ссылки, чтобы выполнить некоторый код после загрузки таблицы стилей.

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: я не могу использовать какие-либо рамки для решения этого

Ответы [ 9 ]

52 голосов
/ 20 марта 2011

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

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;
}
10 голосов
/ 20 мая 2010

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

В приведенном выше коде таблица cssStyles - DOMElement.

4 голосов
/ 14 апреля 2010

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

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

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

3 голосов
/ 24 марта 2011

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

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

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

3 голосов
/ 17 января 2011

Все заслуги перед Тобиасом выше, но здесь есть небольшое расширение того, что он сказал:

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));
2 голосов
/ 17 марта 2011

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

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
});
1 голос
/ 01 августа 2013

Эта функция поддерживается во всех браузерах, а также в ситуациях как с несколькими доменами, так и с одним и тем же доменом, а также обрабатывает внедрение 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;
};
0 голосов
/ 21 января 2014

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

"onload" in link === true

Итак, мое решение состоит в том, чтобы обнаружить браузер Android от userAgent, а затем дождаться какого-то специального правила 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();
}

Демо: http://codepen.io/malyw/pen/AuCtH

0 голосов
/ 14 апреля 2010

У href нет события загрузки, которое вам нужно применить, так как сама страница загружается, например,

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

}

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...