代码之家  ›  专栏  ›  技术社区  ›  David Hellsing

链接元素加载

  •  38
  • David Hellsing  · 技术社区  · 16 年前

    是否仍要为一个用户监听onload事件 <link>

    出厂价:

    var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = 'styles.css';
    
    link.onload = link.onreadystatechange = function(e) {
        console.log(e);
    };
    

    这适用于 <script> 元素,但不是 < . 还有别的办法吗? 我只需要知道外部样式表中的样式何时应用于DOM。

    注入一个隐藏的 <iframe> < 向头部,倾听声音 window.onload iframe中的事件?它应该在css加载时触发,但它可能不能保证它在顶部窗口中加载。。。

    10 回复  |  直到 6 年前
        1
  •  8
  •   Peter Jaric    16 年前

    这是一种黑客行为,但是如果你可以编辑CSS,你可以添加一个特殊的样式(没有明显的效果),你可以在这篇文章中使用这种技术来聆听: http://www.west-wind.com/weblog/posts/478985.aspx

    在页面中需要一个元素,该元素具有CSS将影响的类或id。当您的代码检测到其样式已更改时,CSS已加载。

    一个黑客,就像我说的:)

        2
  •  21
  •   mlangenberg    11 年前

    今天,所有现代浏览器都支持链接标签上的onload事件。所以我会保护黑客,比如创建img元素和设置onerror:

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

    次要更新:

    正如Michael所指出的,有些浏览器例外我们总是想应用hack。在咖啡脚本中:

    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
    
        3
  •  3
  •   zpavlinovic    13 年前

    Image 物体及其捕捉 onerror 事件。问题是浏览器不知道这个资源是不是一个图像,所以它会尝试获取它无论如何。然而,由于它不是一个实际的图像,它将触发 处理程序。

    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;
    

        4
  •  3
  •   Serg Hospodarets    12 年前

    例如,Android浏览器不支持元素的“onload”/“onreadystatechange”事件: http://pieisgood.org/test/script-link-events/

    "onload" in link === true
    

    因此,我的解决方案是从userAgent检测Android浏览器,然后等待样式表中的一些特殊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

        5
  •  2
  •   Peter Jaric    16 年前

    因为你不喜欢我的黑客:)我四处寻找别的方法,发现 one by brothercake .

        6
  •  1
  •   garlon4    14 年前

    另一种方法是检查加载了多少样式表。例如:

    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);
    }
    
        7
  •  0
  •   sje397    15 年前

    这个把戏是从 xLazyLoader jQuery plugin :

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

    演示 here

        8
  •  0
  •   gblazex    15 年前

    你要么需要一个你知道的特定元素,要么如果你控制CSS文件,你可以为此插入一个虚拟元素。当css文件的内容应用于DOM时,这段代码将使回调运行。

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

    如果在文档底部使用此代码,则可以移动 埃尔 在计时器之外的变量,以便获取元素一次。但是,如果您想将处理程序附加到文档的某个位置(如头部),则应该保持代码的原样。

    注:在FF 3+、IE 5.5+、铬上测试

        9
  •  0
  •   matsko    15 年前
        10
  •  0
  •   sandstrom    9 年前
    // 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);
      });
    };
    
        11
  •  0
  •   user985399 user985399    7 年前

    // 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/tachyons@4.10.0/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 ..... */
    }
    

    this link 也就是说:

    幕后发生的是浏览器试图加载 中的CSS 元素,因为样式表不是 图像,图像 元素抛出 事件并执行我们的 功能。谢天谢地,浏览器会在 确定它不是图像并启动 一个错误 事件。

    css.onload 并添加该代码作为回退,以覆盖2011年以前的浏览器 只有Opera和internetexplorer分别支持onload事件和onreadystatechange .

    here 这也是我的复制品,应该为我的诚实而受到惩罚:P