javascript创建css、js,onload触发callback兼容主流浏览器的实现

http://www.fantxi.com/blog/archives/load-css-js-callback/

由于需要写个函数,既可以加载css,又可以加载js,所以对各主流浏览器对加载js、css后是否触发onload事件做了个测试。当然,为了兼容,首先要考虑的是会用到onload和onreadystatechange,但他们并不是万能的。加载js文件onload触发callback不算大问题。css比较特殊,因为Webkeit/FF下加载css不会触发onload事件。所以研究了一晚上才找到个兼容的办法,分享如下:

首先测试元素直接写在页面

  1. <link onload="alert(‘css onload‘)" rel="stylesheet" href="http://localhost/css/123.css"/>
  2. <script onload="alert(‘js onload‘)" src="http://localhost/123.js"></script>
  3. <link onreadystatechange="alert(‘css readystatechange‘)" rel="stylesheet" href="http://localhost/css/123.css"/>
  4. <script onreadystatechange="alert(‘js readystatechange‘)" src="http://localhost/123.js"></script>

CSS onload: 支持: IE6-9/OP, 不支持: FF/Webkit(SF/CM)
JS onload: 支持: IE9/OP/FF/Webkit, 不支持: IE6-8

CSS onreadystatechange: 支持: IE6-9, 不支持: OP/FF/Webkit
JS onreadystatechange: 支持: IE6-9, 不支持: OP/FF/Webkit

测试js创建元素

  1. var doc = document,
  2. head = doc.getElementsByTagName("head")[0],
  3. css, js;
  4. css = doc.createElement(‘link‘);
  5. css.href = ‘http://localhost/123.css?2‘;
  6. css.rel = ‘stylesheet‘;
  7. head.appendChild(css);
  8. js = doc.createElement(‘script‘);
  9. js.src = ‘http://localhost/123.js?2‘;
  10. head.appendChild(js);
  11. css.onload = function(){
  12. alert(‘css onload‘)
  13. }
  14. js.onload = function(){
  15. alert(‘js onload‘)
  16. }
  17. css.onreadystatechange = function(){
  18. alert(‘css readystatechange‘)
  19. //alert(this.readyState) //IE可以得到loading/complete, OP为undefined
  20. }
  21. js.onreadystatechange = function(){
  22. alert(‘js readystatechange‘)
  23. //alert(this.readyState) //IE可以得到loading/loaded, OP为loaded
  24. }

CSS/JS onload:(同元素直接写在页面是一样的)

CSS onreadystatechange: 支持: IE6-9/OP, 不支持: FF/Webkit (这里有区别,OP支持js创建的css元素,但readyState为undefined)
JS onreadystatechange: 支持: IE6-9/OP, 不支持: FF/Webkit (这里有区别,OP支持js创建的js元素,readyState为loaded)

所以为了更大的兼容,onload、onreadystatechange都要写上,代码类似下面:

  1. // 先把js或者css加到页面: head.appendChild(node);
  2. // onload为IE6-9/OP下创建CSS的时候,或IE9/OP/FF/Webkit下创建JS的时候
  3. // onreadystatechange为IE6-9/OP下创建CSS或JS的时候
  4. node.onload = node.onreadystatechange = function(){
  5. // !this.readyState 为不支持onreadystatechange的情况,或者OP下创建CSS的情况
  6. // this.readyState === "loaded" 为IE/OP下创建JS的时候
  7. // this.readyState === "complete" 为IE下创建CSS的时候
  8. if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") {
  9. node.onload = node.onreadystatechange = null; //防止IE内存泄漏
  10. alert(‘loaded, run callback‘);
  11. }
  12. }

jquery、kissy的源码,判断加载成功的核心部分差不多都这样实现的。

存在的问题:
1、当浏览器同时支持onload、onreadystatechange的情况会触发上面的函数两次,
比如:
IE9加载JS的时候,会alert两次,加载CSS的时候,alert一次,注释掉“onload、readystatechange=null”,alert两次。
OP加载JS/CSS,alert一次,把“onload、readystatechange=null”注释也会alert两次。
解决:
先在外部设定个变量isLoaded = false;
"if (!this.readyState..."上面加上个判断,如果已经加载成功就返回,比如:if (isLoaded) { return; }
"node.onload =..."上面加上 isLoaded = ture;
JQ有没有加这个我忘记了、KS应该是加了类似的判断了。

2、这个方法加载JS调用callback是兼容性没问题了,但是加载CSS再callback支持情况不同了:
IE6-9/OP可以成功alert,但是FF/Webkit不支持css的onload,解决办法:

2.1、读取cssRules的length来判断是否加载成功,缺点不能跨域读取(非IE)。

  1. var doc = document,
  2. head = document.getElementsByTagName( ‘head‘ )[0],
  3. link = doc.createElement(‘link‘);
  4. //link.href = ‘http://xxx.com/123.css‘; //跨域
  5. link.href = ‘http://localhost/123.css‘;
  6. link.rel = ‘stylesheet‘;
  7. head.appendChild( link );
  8. var sheet, cssRules;
  9. if ( ‘sheet‘ in link ) { //FF/CM/OP
  10. sheet = ‘sheet‘; cssRules = ‘cssRules‘;
  11. }
  12. else { //IE
  13. sheet = ‘styleSheet‘; cssRules = ‘rules‘;
  14. }
  15. var _timer1 = setInterval( function() { // 通过定时器检测css是否加载成功
  16. try {
  17. if ( link[sheet] && link[sheet][cssRules].length ) { // css被成功加载
  18. // console.log(link[sheet][cssRules]);
  19. clearInterval( _timer1 ); // 清除定时器
  20. clearTimeout( _timer2 );
  21. alert(‘loaded, run callback‘); // 加载成功执行callback
  22. }
  23. } catch( e ) {
  24. // FF看到的可能的报错:
  25. //本地:nsresult: "0x8053000f (NS_ERROR_DOM_INVALID_ACCESS_ERR)" ,因为没加载完成还不能读取,加载完毕就不会报错了
  26. //跨域:Security error, code: "1000" nsresult: "0x805303e8",因为不能跨域读取CSS。。。
  27. //关于跨域访问:FF/OP/CM都禁止,IE6-9都可以跨域读取css。
  28. } finally {}
  29. }, 20 ),
  30. // 创建超时定时器,如果过10秒没检测到加载成功
  31. _timer2 = setTimeout( function() {
  32. clearInterval( _timer1 ); // 清除定时器
  33. clearTimeout( _timer2 );
  34. alert(‘loaded ? run callback‘); // 都过了这么长时间了,虽然没判断加载成功也执行callback(这里可能本身就加载失败,也可能是跨域的情况)
  35. }, 10000 );
  36. //@See: http://stackoverflow.com/questions/5537622/dynamically-loading-css-file-using-javascript-with-callback-without-jquery

2.2、创建div#hack4loaded,并添加到页面,然后定时读取div的样式,如果样式是css里面设置的就说明加载成功,此方法不存在跨域问题,所有浏览器都OK。(css里面加上一个样式: #hack4loaded{display:none})

  1. var doc = document,
  2. head = doc.getElementsByTagName(‘head‘)[0],
  3. link = doc.createElement(‘link‘);
  4. link.href = ‘http://localhost/123.css‘;
  5. link.rel = ‘stylesheet‘;
  6. head.appendChild( link );
  7. var div  = document.createElement(‘div‘);
  8. div.id = ‘hack4loaded‘;
  9. var getStyle = function(name){ //获取css里面设置的元素样式
  10. if(div.currentStyle){ // IE/OP
  11. return div.currentStyle[name];
  12. }else{ // FF/CM
  13. return div.ownerDocument.defaultView.getComputedStyle(div, null)[name];
  14. }
  15. };
  16. document.body.appendChild(div); // 添加到页面
  17. //创建定时器,读取创建的div的样式是否是已经在css里面设置好的
  18. var _timer1= setInterval( function() {
  19. //console.log(getStyle(‘display‘));
  20. if (‘none‘ === getStyle(‘display‘)) { //样式和css里面设置的一样,说明加载成功
  21. clearInterval( _timer1 ); // 清除定时器
  22. clearTimeout( _timer2 );
  23. div.parentNode.removeChild(div); //移除div
  24. alert(‘loaded, run callback‘); // 加载成功执行callback
  25. }
  26. }, 50 ),
  27. // 创建超时定时器,防止css文件加载失败的情况
  28. _timer2 = setTimeout( function() {
  29. clearInterval( _timer1 ); // 清除定时器
  30. clearTimeout( _timer2 );
  31. alert(‘fail to load‘); // 这个没加载成功的可能性很大,再就是网速太慢超时了
  32. }, 10000 );

所以总结如下:

javascript创建js或者css,可以兼容浏览器在onload时触发callback。
只要把上面的“node.onload = node.onreadystatechange = function()”方法,再结合2.2的创建div#hack4loaded的方法结合再一起,就可以创建一个比较完美的支持加载js、css,并可以在文件加载完毕触发callback的函数。

由于IE/OP支持css的onload,所以写这个方法的时候可以考虑非IE/OP才用2.2的方法判断css加载完成。

时间: 2024-10-20 15:16:05

javascript创建css、js,onload触发callback兼容主流浏览器的实现的相关文章

(转)兼容主流浏览器的CSS透明代码

透明往往能产生不错的网页视觉效果下面是兼容主流浏览器的CSS透明代码.transparent_class { filter:alpha(opacity=50); -moz-opacity:0.5; -khtml-opacity: 0.5; opacity: 0.5; } filter:alpha(opacity=50):这个是为IE6设的,可取值在0-100,其它三个0到1.-moz-opacity:0.5; 这个是为了支持一些老版本的Mozilla浏览器.-khtml-opacity: 0.5

兼容主流浏览器的CSS透明代码

收集一个兼容主流浏览器的透明CSS代码 filter:alpha(opacity=10); -moz-opacity:0.1; -khtml-opacity: 0.1; opacity: 0.1;

将内容复制到剪切板兼容主流浏览器的解决方案

html : <body> <div class="demo-area"> <label for="copy-input">输入要复制到剪切板的文字:</label><br> <textarea id="copy-input" cols="30" rows="10"></textarea><br> <but

加入收藏兼容主流浏览器代码

//加入收藏 function AddFavorite(){ if (document.all) { addToBookMark(window.location.href, document.title); } else if (window.sidebar) { addToBookMark(document.title, window.location.href); } } function addToBookMark(url,title){ var ua = navigator.userAg

jQuery+CSS 简单代码实现遮罩层( 兼容主流浏览器 )

/* ** jQuery版本:jQuery-1.8.3.min.js ** 浏览器:Chrome( v31.0.1650.63 m ),IE11,Firefox( v32.0.1 ),IETester下IE8-IE10** Author:博客园小dee */ 比起使用注册页和登陆页,网站在当前页使用遮罩层注册和登陆的用户体验要好不少.这里使用jQuery和CSS实现一个简单的遮罩效果. 在页面点击"注册",出现一层有不透明度的黑色遮罩:遮罩层的上方是注册框:此时无法点击页面上除注册框外

通用ajax请求方法封装,兼容主流浏览器

ajax简介 没有AJAX会怎么样?普通的ASP.Net每次执行服务端方法的时候都要刷新当前页面.如果没有AJAX,在youku看视频的过程中如果点击了"顶.踩".评论.评论翻页,页面就会刷新,视频就会被打断.开发一个看效果:用<video src="diaosi.mp4" autoplay controls></video>播放视频(只有支持html5的浏览器能播放),然后放一个"赞"按钮的功能(赞的数量存到数据库),看

实时监听input输入的变化(兼容主流浏览器)

遇到如此需求,首先想到的是change事件,但用过change的都知道只有在input失去焦点时才会触发,并不能满足实时监测的需求,比如监测用户输入字符数. 在经过查阅一番资料后,欣慰的发现firefox等现代浏览器的input有oninput这一属性,可以用三种方式使用它: 1,内嵌元素方式(属性编辑方式) <input id="test" oninput="console.log('input');" type="text" />

[转] 实时监听input输入的变化(兼容主流浏览器)

遇到如此需求,首先想到的是change事件,但用过change的都知道只有在input失去焦点时才会触发,并不能满足实时监测的需求,比如监测用户输入字符数. 在经过查阅一番资料后,欣慰的发现firefox等现代浏览器的input有oninput这一属性,可以用三种方式使用它: 1,内嵌元素方式(属性编辑方式) <input id="test" oninput="console.log('input');" type="text" />

DIV JS CSS 轻量级弹出层 兼容各浏览器

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Typ