YAOHAIXIAO.COM

HTML(5),CSS(3),JavaScript,DOM,Ajax,JSON,Front-end technologies & Yaohaixiao

热门标签:JavaScript Performance 前端开发 前端性能优化 原创

Rss

Home » Frontend » JavaScript » DOM » JavaScript 如何判断 CSS 文件加载完毕

JavaScript 如何判断 CSS 文件加载完毕

之前我写过《如何用JavaScript动态创建link标签到head里》,今天接着这个话题说下去,说说 JavaScript 如何判断 CSS 文件记载完毕。呵呵,今天的话题应该算是上个话题的姊妹篇。我们动态创建的CSS文件,如何知道添加的CSS文件加载完毕了呢?

要判断这个 CSS 文件是否加载完毕,各个浏览器的做法差异比较大,这次要说IE浏览器做的不错,我们可以直接通过onload方法来处理CSS加载完成以后的处理:

// 代码节选至seajs
function styleOnload(node, callback) {
    // for IE6-9 and Opera
    if (node.attachEvent) {
      node.attachEvent('onload', callback);
      // NOTICE:
      // 1. "onload" will be fired in IE6-9 when the file is 404, but in
      // this situation, Opera does nothing, so fallback to timeout.
      // 2. "onerror" doesn't fire in any browsers!
    }
}	

很遗憾,这次在其他的浏览器中,想判断CSS是否加载完成就不是那么方便了,FF,webkit可以通过node.sheet.cssRules属性是否存在来判断是否加载完毕。而且需要使用setTimeout间隔事件轮询:

// 代码节选至seajs	
function poll(node, callback) {
    if (callback.isCalled) {
      return;
    }

    var isLoaded = false;

    if (/webkit/i.test(navigator.userAgent)) {//webkit
      if (node['sheet']) {
        isLoaded = true;
      }
    }
    // for Firefox
    else if (node['sheet']) {
      try {
        if (node['sheet'].cssRules) {
          isLoaded = true;
        }
      } catch (ex) {
        // NS_ERROR_DOM_SECURITY_ERR
        if (ex.code === 1000) {
          isLoaded = true;
        }
      }
    }

    if (isLoaded) {
      // give time to render.
      setTimeout(function() {
        callback();
      }, 1);
    }
    else {
      setTimeout(function() {
        poll(node, callback);
      }, 1);
    }
  }	
  
setTimeout(function() {
     poll(node, callback);
}, 0);  

SeaJS给出的完整的处理是这样的:

function styleOnload(node, callback) {
    // for IE6-9 and Opera
    if (node.attachEvent) {
      node.attachEvent('onload', callback);
      // NOTICE:
      // 1. "onload" will be fired in IE6-9 when the file is 404, but in
      // this situation, Opera does nothing, so fallback to timeout.
      // 2. "onerror" doesn't fire in any browsers!
    }
    // polling for Firefox, Chrome, Safari
    else {
      setTimeout(function() {
        poll(node, callback);
      }, 0); // for cache
    }
  }

  function poll(node, callback) {
    if (callback.isCalled) {
      return;
    }

    var isLoaded = false;

    if (/webkit/i.test(navigator.userAgent)) {//webkit
      if (node['sheet']) {
        isLoaded = true;
      }
    }
    // for Firefox
    else if (node['sheet']) {
      try {
        if (node['sheet'].cssRules) {
          isLoaded = true;
        }
      } catch (ex) {
        // NS_ERROR_DOM_SECURITY_ERR
        if (ex.code === 1000) {
          isLoaded = true;
        }
      }
    }

    if (isLoaded) {
      // give time to render.
      setTimeout(function() {
        callback();
      }, 1);
    }
    else {
      setTimeout(function() {
        poll(node, callback);
      }, 1);
    }
  }

// 我的动态创建LINK函数
function createLink(cssURL,lnkId,charset,media){	
    var head = document.getElementsByTagName('head')[0],
        linkTag = null;
		
	if(!cssURL){
	    return false;
	}
   	
    linkTag = document.createElement('link');
	linkTag.setAttribute('id',(lnkId || 'dynamic-style'));
	linkTag.setAttribute('rel','stylesheet');
	linkTag.setAttribute('charset',(charset || 'utf-8'));
	linkTag.setAttribute('media',(media||'all'));
	linkTag.setAttribute('type','text/css');
    linkTag.href = cssURL;	
	
    head.appendChild(linkTag);	
}

function loadcss(){
    var styleNode = createLink('http://www.yaohaixiao.com/wp-content/themes/BlueNight/style.css');
	
    styleOnload(styleNode,function(){
        alert("loaded");
    });
}

在看到seajs的代码的时候,我立刻想起了我看到Diego Perini的另一个解决方案:

/*
 * Copyright (C) 2010 Diego Perini
 * All rights reserved.
 *
 * cssready.js - CSS loaded/ready state notification
 *
 * Author: Diego Perini <diego.perini at gmail com>
 * Version: 0.1
 * Created: 20100616
 * Release: 20101104
 *
 * License:
 *  http://javascript.nwbox.com/cssready/MIT-LICENSE
 * Download:
 *  http://javascript.nwbox.com/cssready/cssready.js
 */

function cssReady(fn, link) {

  var d = document,
  t = d.createStyleSheet,
  r = t ? 'rules' : 'cssRules',
  s = t ? 'styleSheet' : 'sheet',
  l = d.getElementsByTagName('link');

  // passed link or last link node
  link || (link = l[l.length - 1]);

  function check() {
    try {
      return link && link[s] && link[s][r] && link[s][r][0];
    } catch(e) {
      return false;
    }
  }

  (function poll() {
    check() && setTimeout(fn, 0) || setTimeout(poll, 100);
  })();

}	

其实,如果你读过jQuery的domready事件的判断的代码,原理也类似。也是通过setTimeout轮询的方式来判断DOM节点是否加载完毕。

还有,Fackbook则是通过在动态创建的CSS样式中包含一个固定的样式,例如#loadcssdom,loadcssdom就是一个高度为1px样式。然后动态创建一个DOM对象,添加这个loadcssdom样式。然后也是setTimeout轮询loadcssdo是否已经有1px的高度了。这个处理方式的解决方案,大家可以下《CSSP: Loading CSS with Javascript – and getting an onload callback.

而《JavaScript Patterns》的作者Stoyan则在他的博客里,比较详细的说明了《When is a stylesheet really loaded?》。

看完了这些,你可能会感叹:汗,判断CSS是否加载完毕,目前还真不是那么容易!其实我这里算是一个抛砖引玉,因为开发中,除了动态加载CSS,我们还要动态加载JavaScript,动态加载HTML的操作,有空我也会写关于动态加载JavaScript的相关内容,不过在那之前,我建议你看看这些:

好了,这次就说这么多了,希望对对大家的开发和学习有帮助!

声明:本文采用BY-NC-SA协议进行授权。转载请注明转自:JavaScript 如何判断 CSS 文件加载完毕

« »

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(Spamcheck Enabled)