webentwicklung-frage-antwort-db.com.de

linkelement onload

Gibt es überhaupt ein Onload-Ereignis für ein <link>-Element?

F.ex:

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';

link.onload = link.onreadystatechange = function(e) {
    console.log(e);
};

Dies funktioniert für <script>-Elemente, jedoch nicht für <link>. Gibt es einen anderen Weg? Ich muss nur wissen, wann die Stile im externen Stylesheet auf das DOM angewendet wurden.

Update:

Wäre es eine Idee, einen versteckten <iframe> zu injizieren, den <link> zum Kopf hinzuzufügen und auf das window.onload-Ereignis im iframe zu achten? Es sollte ausgelöst werden, wenn die css geladen wird. Es kann jedoch nicht garantiert werden, dass sie im oberen Fenster geladen wird ...

38
David Hellsing

Dies ist eine Art Hack, aber wenn Sie das CSS bearbeiten können, können Sie einen speziellen Stil (ohne sichtbaren Effekt) hinzufügen, auf den Sie mit der Technik in diesem Beitrag achten können: http: //www.west-wind .com/weblog/posts/478985.aspx

Sie benötigen ein Element auf der Seite, das eine Klasse oder eine ID hat, auf die sich das CSS auswirkt. Wenn Ihr Code feststellt, dass sich sein Stil geändert hat, wurde das CSS geladen.

Ein Hack wie gesagt :)

7
Peter Jaric

Heute unterstützen alle modernen Browser das Onload-Ereignis bei Link-Tags. Ich würde also Hacks schützen, z. B. ein img-Element erstellen und den Onerror festlegen:

if !('onload' in document.createElement('link')) {
  imgTag = document.createElement(img);
  imgTag.onerror = function() {};
  imgTag.src = ...;
} 

Dies sollte eine Problemumgehung für FF-8 und frühere sowie ältere Safari- und Chrome-Versionen bieten.

kleines Update:

Wie Michael betonte, gibt es einige Browser-Ausnahmen, für die wir immer den Hack anwenden wollen. In Kaffeescript:

isSafari5: ->
  !!navigator.userAgent.match(' Safari/') &&
      !navigator.userAgent.match(' Chrom') &&
      !!navigator.userAgent.match(' Version/5.')

# Webkit: 535.23 and above supports onload on link tags.
isWebkitNoOnloadSupport: ->
  [supportedMajor, supportedMinor] = [535, 23]
  if (match = navigator.userAgent.match(/\ AppleWebKit\/(\d+)\.(\d+)/))
    match.shift()
    [major, minor] = [+match[0], +match[1]]
    major < supportedMajor || major == supportedMajor && minor < supportedMinor
16
mlangenberg

In Chrome (nicht in anderen Browsern getestet) habe ich das CSS mit einem Image-Objekt geladen und dessen onerror-Ereignis abgefangen. Der Browser weiß nicht, ob es sich bei dieser Ressource um ein Bild handelt oder nicht, daher versucht es es trotzdem. Da es sich jedoch nicht um ein tatsächliches Bild handelt, werden onerror-Handler ausgelöst. 

var css = new Image();
css.onerror = function() {
    // method body
}
// Set the url of the CSS. In link case, link.href
// This will make the browser try to fetch the resource.
css.src = url_of_the_css;

Wenn die Ressource bereits abgerufen wurde, trifft diese Abrufanforderung auf den Cache.

3
bellpeace

Z.B. Android-Browser unterstützt keine "onload"/"onreadystatechange" -Ereignisse für element: http://pieisgood.org/test/script-link-events/
Aber es kommt zurück:

"onload" in link === true

Meine Lösung besteht also darin, den Android-Browser von userAgent zu erkennen und dann auf eine spezielle CSS-Regel in Ihrem Stylesheet zu warten (z. B. für "body" -Ränder zurücksetzen).
Wenn es kein Android-Browser ist und "onload" -Ereignisse unterstützt, werden wir es verwenden:

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

2

Da du meinen Hack nicht gemocht hast :) Ich habe mich nach einem anderen Weg umgesehen und gefunden einen von brothercake .

Grundsätzlich wird vorgeschlagen, das CSS mithilfe von AJAX zum Bringen des Browsers in den Browser zu bringen und dann die Linklast als sofort zu behandeln, da das CSS zwischengespeichert wird. Dies wird wahrscheinlich nicht jedes Mal funktionieren (da bei manchen Browsern beispielsweise der Cache deaktiviert wurde), aber fast immer. 

1
Peter Jaric

Eine andere Möglichkeit besteht darin, zu überprüfen, wie viele Stylesheets geladen werden. Zum Beispiel:

Mit "css_filename" die URL oder den Dateinamen der css-Datei und "callback" eine Callback-Funktion, wenn die css geladen wird:

var style_sheets_count=document.styleSheets.length;
var css = document.createElement('link');
css.setAttribute('rel', 'stylesheet');
css.setAttribute('type', 'text/css');
css.setAttribute('href', css_filename);
document.getElementsByTagName('head').item(0).appendChild(css);
include_javascript_wait_for_css(style_sheets_count, callback, new Date().getTime());

function include_javascript_wait_for_css(style_sheets_count, callback, starttime)
/* Wait some time for a style sheet to load.  If the time expires or we succeed
 *  in loading it, call a callback function.
 * Enter: style_sheet_count: the original number of style sheets in the
 *                           document.  If this changes, we think we finished
 *                           loading the style sheet.
 *        callback: a function to call when we finish loading.
 *        starttime: Epoch when we started.  Used for a timeout. 12/7/11-DWM */
{  
   var timeout = 10000; // 10 seconds
   if (document.styleSheets.length!=style_sheets_count || (new Date().getTime())-starttime>timeout)
      callback();
   else
      window.setTimeout(function(){include_javascript_wait_for_css(style_sheets_count, callback, starttime)}, 50);
}
1
garlon4

Dieser Trick wird aus dem jQuery-Plugin xLazyLoader ausgeliehen:

var count = 0;

(function(){
  try {
    link.sheet.cssRules;
  } catch (e) {
    if(count++ < 100)
      cssTimeout = setTimeout(arguments.callee, 20);
    else
      console.log('load failed (FF)');
    return;
  };
  if(link.sheet.cssRules && link.sheet.cssRules.length == 0) // fail in chrome?
    console.log('load failed (Webkit)');
  else
    console.log('loaded');
})();

In FF (3.6.3) und Chrome (Linux - 6.0.408.1 dev) getestet und lokal getestet

Demo hier (Beachten Sie, dass dies beim Cross-Site-CSS-Laden nicht funktioniert, wie in der Demo unter FF)

0
sje397

Dies ist eine browserübergreifende Lösung

// Your css loader
var d = document,
    css = d.head.appendChild(d.createElement('link'))

css.rel = 'stylesheet';
css.type = 'text/css';
css.href = "https://unpkg.com/[email protected]/css/tachyons.css"

// Add this  
if (typeof s.onload != 'undefined') s.onload = myFun;
} else {
    var img = d.createElement("img");
    img.onerror = function() {
      myFun();
      d.body.removeChild(img);
    }
    d.body.appendChild(img);
    img.src = src;
}

function myFun() {
    /* ..... PUT YOUR CODE HERE ..... */
}

Die Antwort basiert auf dieser Link das sagt:

Hinter den Kulissen versucht der Browser, das CSS in das Element img zu laden. Da es sich bei einem Stylesheet nicht um einen Bildtyp handelt, wird das Element Das Element img löst das Ereignis onerror aus und führt unsere Funktion aus. Zum Glück laden Browser die gesamte CSS-Datei, bevor sie feststellen, dass es sich nicht um ein Bild handelt, und das Ereignis onerror auslösen.

In modernen Browsern können Sie css.onload ausführen und diesen Code als Ersatz für alte Browser bis 2011 hinzufügen, wenn only Opera und Internet Explorer unterstützt) das onload-Ereignis bzw. onreadystatechange.

Anmerkung: Ich habe hier geantwortet und es ist mein Duplikat und verdient, für meine Ehrlichkeit bestraft zu werden: P

// this work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// if you want to use Promise in an non-es6 browser, add an ES6 poly-fill (or rewrite to use a callback)

let fetchStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.onload = resolve;
    link.href = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};
0
sandstrom

Sie benötigen entweder ein bestimmtes Element, dessen Stil Sie kennen, oder wenn Sie die CSS-Datei steuern, können Sie zu diesem Zweck ein Dummy-Element einfügen. Mit diesem Code wird Ihr Callback genau ausgeführt, wenn der Inhalt der CSS-Datei auf das DOM angewendet wird. 

// dummy element in the html
<div id="cssloaded"></div>

// dummy element in the css
#cssloaded { height:1px; }

// event handler function
function cssOnload(id, callback) {
  setTimeout(function listener(){
    var el = document.getElementById(id),
        comp = el.currentStyle || getComputedStyle(el, null);
    if ( comp.height === "1px" )
      callback();
    else
      setTimeout(listener, 50);
  }, 50)
}

// attach an onload handler
cssOnload("cssloaded", function(){ 
  alert("ok"); 
});

Wenn Sie diesen Code am unteren Rand des Dokuments verwenden, können Sie die Variablen el und comp außerhalb des Timers verschieben, um das Element einmal abzurufen. Wenn Sie den Handler jedoch irgendwo im Dokument (wie den Kopf) anhängen möchten, sollten Sie den Code so belassen, wie er ist.

Hinweis: Getestet mit FF 3+, IE 5.5+, Chrome

0
gblazex

Das xLazyLoader-Plugin schlägt fehl, da die cssRules-Eigenschaften für Stylesheets, die zu anderen Domänen gehören, verborgen sind (bricht die gleiche Origin-Richtlinie). Sie müssen also den ownerNode und die owningElements miteinander vergleichen.

Hier finden Sie eine ausführliche Erläuterung der Aufgaben: http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/

0
matsko