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 相关文章推荐
小议javascript 设计模式 推荐
Oct 28 Javascript
js jquery获取随机生成id的服务器控件的三种方法
Jul 11 Javascript
javascript jq 弹出层实例
Aug 25 Javascript
jquery增加时编辑jqGrid(实例代码)
Nov 08 Javascript
Web程序员必备的7个JavaScript函数
Jun 14 Javascript
js获取浏览器的各种属性
Apr 27 Javascript
webpack-dev-server自动更新页面方法
Feb 22 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
Sep 19 Javascript
angular将html代码输出为内容的实例
Sep 30 Javascript
layui的表单验证支持ajax判断用户名是否重复的实例
Sep 06 Javascript
使用原生JS实现滚轮翻页效果的示例代码
May 31 Javascript
vue实现移动端input上传视频、音频
Aug 18 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
thinkphp中多表查询中防止数据重复的sql语句(必看)
2016/09/22 PHP
微信支付之JSAPI公众号支付详解
2019/05/15 PHP
一步一步教你写一个jQuery的插件教程(Plugin)
2009/09/03 Javascript
Ajax搜索结果页面下方的分页按钮的生成
2012/04/05 Javascript
js类定义函数时用prototype与不用的区别示例介绍
2014/06/10 Javascript
js跨域问题浅析及解决方法优缺点对比
2014/11/08 Javascript
javascript实现画不相交的圆
2015/04/07 Javascript
jQuery菜单插件用法实例
2015/07/25 Javascript
Vue导出json数据到Excel电子表格的示例
2017/12/04 Javascript
详解Angular cli配置过程记录
2019/11/07 Javascript
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)
2020/01/14 Javascript
webpack中的模式(mode)使用详解
2020/02/20 Javascript
ant-design-vue按需加载的坑的解决
2020/05/14 Javascript
JavaScript中跨域问题的深入理解
2021/03/04 Javascript
[00:36]TI7不朽珍藏III——斯温不朽展示
2017/07/15 DOTA
Python中的测试模块unittest和doctest的使用教程
2015/04/14 Python
解决Python pandas plot输出图形中显示中文乱码问题
2018/12/12 Python
python实现抽奖小程序
2020/04/15 Python
使用Python的OpenCV模块识别滑动验证码的缺口(推荐)
2019/05/10 Python
Anaconda之conda常用命令介绍(安装、更新、删除)
2019/10/06 Python
Python调用Windows命令打印文件
2020/02/07 Python
python调用百度AI接口实现人流量统计
2021/02/03 Python
详解CSS3实现响应式手风琴效果
2020/06/10 HTML / CSS
h5移动端调用支付宝、微信支付的实现
2020/06/08 HTML / CSS
苹果音乐订阅:Apple Music
2018/08/02 全球购物
英国露营设备和户外服装购物网站:Simply Hike
2019/05/05 全球购物
加拿大在线隐形眼镜和眼镜店:VisionPros
2019/10/06 全球购物
八年级数学教学反思
2014/01/31 职场文书
物流专业自荐信
2014/05/23 职场文书
个人委托书范本
2014/09/13 职场文书
公务员上班玩游戏检讨书
2014/09/17 职场文书
幼儿园辞职信范文
2015/02/27 职场文书
郭明义观后感
2015/06/08 职场文书
2015年行政管理人员工作总结
2015/10/15 职场文书
Tomcat配置访问日志和线程数
2022/05/06 Servers