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 相关文章推荐
利用JQuery+EasyDrag 实现弹出可拖动的Div,同时向Div传值,然后返回Div选中的值
Oct 24 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
May 07 Javascript
js、css、img等浏览器缓存问题的2种解决方案
Oct 23 Javascript
js日期联动示例
May 02 Javascript
js获取当前页面的url网址信息
Jun 12 Javascript
jQuery实现切换页面过渡动画效果
Oct 29 Javascript
jQuery+css实现的切换图片功能代码
Jan 27 Javascript
JS HTML5实现拖拽移动列表效果
Aug 27 Javascript
利用JS判断鼠标移入元素的方向
Dec 11 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
Apr 10 Javascript
在Vue中使用HOC模式的实现
Aug 23 Javascript
js中Object.create实例用法详解
Oct 05 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
PHP实现网上点歌(二)
2006/10/09 PHP
IIS6+PHP5+MySQL5+Zend Optimizer+phpMyAdmin安装配置图文教程 2009年
2009/06/08 PHP
PHP函数spl_autoload_register()用法和__autoload()介绍
2012/02/04 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
2015/12/10 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
学习YUI.Ext基础第一天
2007/03/10 Javascript
javascript 一个自定义长度的文本自动换行的函数
2007/08/19 Javascript
javascript 随机展示头像实现代码
2011/12/06 Javascript
js Array对象的扩展函数代码
2013/04/24 Javascript
js获取下拉列表框中的value和text的值示例代码
2014/01/11 Javascript
完美兼容各大浏览器的jQuery插件实现图片切换特效
2014/12/12 Javascript
DOM基础教程之使用DOM设置文本框
2015/01/20 Javascript
Javascript 拖拽的一些简单的应用(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
JavaScript数据类型检测代码分享
2015/01/26 Javascript
javascript封装addLoadEvent实现页面同时加载执行多个函数的方法
2016/07/25 Javascript
AngularJS  $modal弹出框实例代码
2016/08/24 Javascript
改变vue请求过来的数据中的某一项值的方法(详解)
2018/03/08 Javascript
解决vue项目打包后提示图片文件路径错误的问题
2018/07/04 Javascript
Vue中多个元素、组件的过渡及列表过渡的方法示例
2019/02/13 Javascript
JS页面动态绘图工具SVG,Canvas,VML介简介
2020/10/16 Javascript
[51:06]2018DOTA2亚洲邀请赛3月29日 小组赛A组 KG VS Liquid
2018/03/30 DOTA
python模拟登录并且保持cookie的方法详解
2017/04/04 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
2018/05/08 Python
python 将日期戳(五位数时间)转换为标准时间
2019/07/11 Python
在Pytorch中计算卷积方法的区别详解(conv2d的区别)
2020/01/03 Python
python实现图片转换成素描和漫画格式
2020/08/19 Python
python3 通过 pybind11 使用Eigen加速代码的步骤详解
2020/12/07 Python
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
HTMl5的存储方式sessionStorage和localStorage详解
2014/03/18 HTML / CSS
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
L’Artisan Parfumeur官网:法国香水品牌
2020/08/11 全球购物
教师年终个人自我评价
2013/10/04 职场文书
团队队名口号大全
2014/06/06 职场文书
代领毕业证委托书
2014/08/02 职场文书
机关党员三严三实心得体会
2014/10/13 职场文书
初中数学教学随笔
2015/08/15 职场文书