javascript: acquisizione dell’evento di caricamento su LINK

Sto provando ad associare un gestore di eventi all’evento load di un tag link, per eseguire codice dopo che un foglio di stile è stato caricato.

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) 

ho provato anche onreadystatechange

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

sfortunatamente nessuno dei due approcci causa l’triggerszione di un avviso. Inoltre, new_element.onload è nullo dopo aver registrato un gestore per l’evento ‘load’ con addEventListener .. è normale?

grazie, Andrew

ps: non posso usare nessun framework per risolvere questo

Per i fogli di stile CSS (non gli elementi LINK in generale) sto usando l’intervallo manuale, facendo la sua lunghezza delle regole. Funziona crossbrowser (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){} 

Nel codice sopra, il cssStylesheet è DOMElement.

Ecco cosa è, a mio parere, una soluzione migliore per questo problema che utilizza il tag IMG e il suo evento onerror. Questo metodo eseguirà il lavoro senza eseguire il ciclo, eseguendo osservanze di stile contorte o caricando file in iframe, ecc. Questa soluzione viene triggersta correttamente quando il file è carico e subito se il file è già memorizzato nella cache (che è ironicamente migliore di come la maggior parte dei DOM caricare eventi gestiscono le risorse memorizzate nella cache). Ecco un post sul mio blog che spiega il metodo – Back Alley Coder post – Mi sono appena stancato di questo non avendo una soluzione legit, buon divertimento!

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

Anche se aggiungi un inline:

  

Non si triggers in FireFox in quanto non esiste un evento onload per gli elementi di link . (Funzionerà in IE)

Tutto il merito va a Tobiasz in alto, ma ecco una piccola espansione su ciò che ha detto:

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

Lo chiameresti con qualcosa di simile (usando jquery):

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

Il link.innerHTML, link.styleSheet e cssRules sono tutti buoni approcci, ma non funzionano per i fogli di stile che appartengono a un dominio al di fuori del dominio di origine (quindi il caricamento del foglio di stile tra siti non riesce). Questo può essere piuttosto inaspettato quando viene utilizzato un sottodominio o un dominio (www per esempio) o viene utilizzato un CNS statico. Ed è piuttosto fastidioso dal momento che gli elementi non hanno restrizioni della stessa origine.

Ecco una soluzione che utilizza il metodo onload per i browser che la supportano (IE e Opera), ma poi utilizza un intervallo di tempo per i browser che non lo fanno e confronta i nodes ownerNode e ownElement per verificare quando il foglio di stile si è fatto strada il DOM.

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

Bel colpo Matt. Ho creato questo aiutante con il tuo commento.

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

Uso:

 var $link = $(''); $('head').append($link); CSSload($link.get(0), function(){ // do something onLoad }); 

Questa funzione ha resaltato su tutti i browser, sia nelle situazioni cross domain che nello stesso dominio, inoltre gestisce l’iniezione di javascript e di fogli di stile.

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

Ad esempio, il browser Android non supporta gli eventi “onload” / “onreadystatechange” per l’elemento: http://pieisgood.org/test/script-link-events/
Ma restituisce:

 "onload" in link === true 

Quindi, la mia soluzione è di rilevare il browser Android da userAgent e quindi attendere qualche regola css speciale nel tuo foglio di stile (ad esempio, resettare i margini “del corpo”).
Se non è un browser Android e supporta l’evento “onload”, lo useremo:

 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

Un href non ha un evento di carico che è necessario applicare le tue cose come la stessa pagina carica ad esempio

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

utilizzare la funzione in questa pagina: http://www.dustindiaz.com/top-ten-javascript/

per aggiungere l’evento l’elemento del corpo (in linea sarebbe)