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

 更新时间:2014年01月17日 15:07:25   作者:  
在多数情况下我们不需要判断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('/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://www.jb51.net * 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 www.jb51.net 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。
好了,这次就说这么多了,希望对对大家的开发和学习有帮助!

相关文章

  • ES6 迭代器 Iterator使用总结

    ES6 迭代器 Iterator使用总结

    ES6引入了Iterator(迭代器)接口,用于顺序访问可迭代对象,Iterator接口提供统一的访问接口,并通过for...of循环供消费,本文给大家介绍ES6 迭代器 Iterator使用总结,感兴趣的朋友跟随小编一起看看吧
    2025-02-02
  • TypeScript接口介绍

    TypeScript接口介绍

    这篇文章主要介绍了TypeScript接口,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。下面我们一起进入文章看看TypeScript接口得具体定义吧,需要的朋友也可以参考一下
    2021-12-12
  • js常用DOM方法详解

    js常用DOM方法详解

    本文主要介绍了js常用的DOM方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • JavaScript实现图片上传并预览并提交ajax

    JavaScript实现图片上传并预览并提交ajax

    这篇文章主要为大家详细介绍了JavaScript实现图片上传并预览并提交ajax,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • 微信小程序vant 输入框问题处理方案

    微信小程序vant 输入框问题处理方案

    这篇文章主要介绍了微信小程序vant输入框问题,本文给大家分享完美解决方案,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • js实现tab选项卡切换功能

    js实现tab选项卡切换功能

    本文主要分享了javascript实现tab选项卡切换功能的示例代码。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • JavaScript知识点整理

    JavaScript知识点整理

    本文是脚本之家小编日常整理的关于javascript知识点,包括javascript拥有的特点,组成部分,数据类型等方面,对javascript知识点相关知识感兴趣的朋友一起学习吧
    2015-12-12
  • JS实现上传图片实时预览功能

    JS实现上传图片实时预览功能

    这篇文章主要介绍了JS实现上传图片实时预览功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-05-05
  • 用js实现的检测浏览器和系统的函数

    用js实现的检测浏览器和系统的函数

    检测各种浏览器、系统的JS代码
    2009-04-04
  • 函数式JavaScript编程指南

    函数式JavaScript编程指南

    函数式JavaScript编程指南...
    2007-02-02

最新评论