Js判断CSS文件加载完毕的具体实现


Posted in Javascript onJanuary 17, 2014

要判断这个 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('/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:
 *  https://3water.com * 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的相关内容,不过在那之前,我建议你看看这些:
    《ensure ? Ensure JavaScripts/HTML/CSS are loaded on-demand when needed》,这个库是专门处理动态加载HTML,CSS,JavaScript的。就像作者介绍的那样:
        ensure is a tiny JavaScript library that provides a handy function ensure which allows you to load JavaScript, HTML, CSS on-demand, and then execute your code. ensure 3water.com ensures that the relevant JavaScript and HTML snippets are already in the browser DOM before executing your code that uses them.
    《Tell CSS that JavaScript is available ASAP》
    看完这个后,你可能就不会纠结:When you're styling parts of a web page that will look and work differently depending on whether JavaScript is available or not。
好了,这次就说这么多了,希望对对大家的开发和学习有帮助!

Javascript 相关文章推荐
js表数据排序 sort table data
Feb 18 Javascript
Javascript+XMLHttpRequest+asp.net无刷新读取数据库数据
Aug 09 Javascript
jquery text()要注意啦
Oct 30 Javascript
用JavaScript玩转游戏物理(一)运动学模拟与粒子系统
Jun 19 Javascript
JavaScript实现找出数组中最长的连续数字序列
Sep 03 Javascript
jQuery中$.each()函数的用法引申实例
May 12 Javascript
JavaScript实现256色转灰度图
Feb 22 Javascript
浅谈在fetch方法中添加header后遇到的预检请求问题
Aug 31 Javascript
vue中锚点的三种方法
Jul 06 Javascript
Vue项目中使用better-scroll实现一个轮播图自动播放功能
Dec 03 Javascript
解决vue里a标签值解析变量,跳转页面,前面加默认域名端口的问题
Jul 22 Javascript
JavaScript实现商品评价五星好评
Nov 30 Javascript
js使用eval解析json(js中使用json)
Jan 17 #Javascript
js window.open弹出新的网页窗口
Jan 16 #Javascript
jQuery$命名冲突怎么办如何解决
Jan 16 #Javascript
jQuery获得内容和属性示例代码
Jan 16 #Javascript
jQuery 追加元素的方法如append、prepend、before
Jan 16 #Javascript
jQuery 设置 CSS 属性示例介绍
Jan 16 #Javascript
jQuery 滑动方法slideDown向下滑动元素
Jan 16 #Javascript
You might like
我的论坛源代码(三)
2006/10/09 PHP
PHP cron中的批处理
2008/09/16 PHP
php imagecreatetruecolor 创建高清和透明图片代码小结
2010/05/15 PHP
Php Image Resize图片大小调整的函数代码
2011/01/17 PHP
php根据日期或时间戳获取星座信息和生肖等信息
2015/10/20 PHP
php的instanceof和判断闭包Closure操作示例
2020/01/26 PHP
使用JavaScript 实现对象 匀速/变速运动的方法
2013/05/08 Javascript
jquery遍历select元素(实例讲解)
2013/12/31 Javascript
javaScript中的this示例学习详解及工作原理
2014/01/13 Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
2014/04/15 Javascript
javascript计时器编写过程与实现方法
2016/02/29 Javascript
Vuejs第十一篇组件之slot内容分发实例详解
2016/09/09 Javascript
BootStrap Validator使用注意事项(必看篇)
2016/09/28 Javascript
微信小程序实现点击文字页面跳转功能【附源码下载】
2017/12/12 Javascript
实例分析vue循环列表动态数据的处理方法
2018/09/28 Javascript
nodejs初始化init的示例代码
2018/10/10 NodeJs
Vue插值、表达式、分隔符、指令知识小结
2018/10/12 Javascript
vue路由守卫,限制前端页面访问权限的例子
2019/11/11 Javascript
[16:43]Heroes19_剃刀(完美)
2014/10/31 DOTA
[02:38]2018DOTA2亚洲邀请赛赛前采访-VGJ.T
2018/04/03 DOTA
Python 返回汉字的汉语拼音
2009/02/27 Python
python之wxPython应用实例
2014/09/28 Python
python中利用Future对象回调别的函数示例代码
2017/09/07 Python
Python 爬取携程所有机票的实例代码
2018/06/11 Python
django进阶之cookie和session的使用示例
2018/08/17 Python
python 划分数据集为训练集和测试集的方法
2018/12/11 Python
Python判断字符串是否xx开始或结尾的示例
2019/08/08 Python
Jmeter HTTPS接口测试证书导入过程图解
2020/07/22 Python
波兰在线杂货店:Polski Koszyk
2019/11/02 全球购物
哥伦比亚加拿大官网:Columbia Sportswear Canada
2020/09/07 全球购物
文员个人求职自荐信
2013/09/21 职场文书
应届生找工作求职信
2014/06/24 职场文书
行政处罚听证告知书
2015/07/01 职场文书
爱鸟护鸟的宣传语
2015/07/13 职场文书
医院岗前培训心得体会
2016/01/08 职场文书
深入解读Java三大集合之map list set的用法
2021/11/11 Java/Android