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 学习笔记01 JQuery初接触
May 06 Javascript
原生js实现类似弹窗抖动效果
Apr 02 Javascript
JavaScript中的setUTCDate()方法使用详解
Jun 11 Javascript
认识Knockout及如何使用Knockout绑定上下文
Dec 25 Javascript
深入剖析JavaScript中的函数currying柯里化
Apr 29 Javascript
jQuery文字横向滚动效果的实现代码
May 31 Javascript
jQuery特殊符号转义的实现
Nov 30 Javascript
详解在HTTPS 项目中使用百度地图 API
Apr 26 Javascript
jQuery内容选择器与表单选择器实例分析
Jun 28 jQuery
vue element-ui table组件动态生成表头和数据并修改单元格格式 父子组件通信
Aug 15 Javascript
JS一次前端面试经历记录
Mar 19 Javascript
如何在现代JavaScript中编写异步任务
Jan 31 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中Smarty模板初体验
2011/08/08 PHP
关于js与php互相传值的介绍
2013/06/25 PHP
PHP自定义错误处理的方法分析
2018/12/19 PHP
document对象execCommand的command参数介绍
2006/08/01 Javascript
用 Javascript 验证表单(form)中的单选(radio)值
2009/09/08 Javascript
JSON 数字排序多字段排序介绍
2013/09/18 Javascript
JavaScript对内存分配及管理机制详细解析
2013/11/11 Javascript
js跳转页面方法实现汇总
2014/02/11 Javascript
悬浮数字的实现案例
2014/02/19 Javascript
javascript中使用正则表达式清理table样式的代码
2020/04/01 Javascript
原生JS实现美图瀑布流布局赏析
2015/09/07 Javascript
基于jQuery实现仿QQ空间送礼物功能代码
2016/05/24 Javascript
js 模仿锚点定位的实现方法
2016/11/19 Javascript
微信小程序开发的四十个技术窍门总结(推荐)
2017/01/23 Javascript
JQuery页面随滚动条动态加载效果的简单实现(推荐)
2017/02/08 Javascript
Jquery实现获取子元素的方法分析
2019/08/24 jQuery
vue中的mescroll搜索运用及各种填坑处理
2019/10/30 Javascript
谈谈我在vue-cli3中用预渲染遇到的坑
2020/04/22 Javascript
js实现限定区域范围拖拉拽效果
2020/11/20 Javascript
[42:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS OpTic
2018/03/31 DOTA
运动检测ViBe算法python实现代码
2018/01/09 Python
python函数修饰符@的使用方法解析
2019/09/02 Python
Python绘制热力图示例
2019/09/27 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
施华洛世奇意大利官网:SWAROVSKI意大利
2018/07/23 全球购物
决定成败的关键——创业计划书
2014/01/24 职场文书
个人自我剖析材料
2014/02/07 职场文书
购房意向书范本
2014/04/01 职场文书
小学生寒假家长评语
2014/04/16 职场文书
学校教师读书活动总结
2014/07/08 职场文书
淘宝好评语句大全
2014/12/31 职场文书
小学班级口号大全
2015/12/25 职场文书
小学班级管理心得体会
2016/01/07 职场文书
Web前端:CSS最强总结 附详细代码
2021/03/31 HTML / CSS
Python代码风格与编程习惯重要吗?
2021/06/03 Python
pytest实现多进程与多线程运行超好用的插件
2022/07/15 Python