HTML+CSS入门 CSS文件动态加载浅析
沉沙 2018-07-17 来源 : 阅读 1187 评论 0

摘要:本篇教程探讨了CSS文件动态加载的相关内容,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS的入门。

前段时间研究了下JS动态加载和执行顺序依赖的东东,把LABJS的源码从头扒了下:LABJS浅析。对于JS加载执行以及下载监控这,项目组在这块做的东西不少,但对于CSS加载这块的质量监控,力度就小得多了。原因很简单:JS下载失败或出错,这个页面基本就废了。CSS下载失败,大部分情况下页面还是可用的,虽然会比较臭。

但对于OPA来说,情况可能就完全不同了,CSS文件加载失败的影响相对就比较大了。

本着生命不息折腾不已的精神,又倒腾了下CSS加载这块的内容,成果如下,鉴于今天晚上11点才下班回家现在已经很困,就直接上代码了,详细分析后面补上~

删掉注释空行其实代码很少,关于如何测试、API调用都在开头声明了,demo可下载 附件 :)

1 /**  
2  * CSS文件加载器,主要功能:动态加载CSS文件,支持加载完成时候的回调(成功 and 失败 情况下)  
3  * 源码实现借鉴:https://github.com/rgrove/lazyload/commit/6caf58525532ee8046c78a1b026f066bad46d32d  
4  * 更多关于CSS加载的坑的讨论,见://www.phpied.com/when-is-a-stylesheet-really-loaded/  
5  *   
6  * 测试方法:1)将文件解压到服务器上(或用fiddler等本地文件替换) 2)访问demo.html即可  
7  *  
8  * @example  
9  *   loadCSS.load('style.css'); 
10  *   loadCSS.load('style.css', function(){ alert('style.css loaded'); }); 
11  *   loadCSS.load('style.css', function(obj){ alert('age is '+obj.age); }, {age: 24}); 
12  *   loadCSS.load(['a.css', 'b.css'], function(){ alert('a.css and b.css are all loaded'); }); 
13  * 
14  * 更多说明:目前只能判断CSS文件加载事件是否完成,至于是否出现404、5XX等,还判断不了 
15  * 曲线救国:回调里判断CSS里定义的某个样式是否存在/生效,借此判断CSS是否下载成功,如下 
16  *   loadCSS.load('sytle.css', function(){ 
17  *      var div = document.createElement('div'); 
18  *      div.className = 'pre_defined_class';  //pre_defined_class 为测试用的预定义类,假设为 .pre_defined_class{display:none;} 
19  *      var value = getStyle(div, 'display'); 
20  *      if(value=='none'){ 
21  *        //成功 
22  *      }else{ 
23  *        //失败 
24  *      } 
25  *   }) 
26  * 
27  * @version 1.0 
28  * @TODO: 1)静态加载的CSS文件的检测(是否成功加载)2)加载配置项 
29  * @author casper  chyingp@gmail.com  
30  *                 //www.cnblogs.com/chyingp 
31  *                 //www.zcool.com.cn/u/346408 
32  *  
33  */ 
34 var LoadCSS = (function () { 
35    
36   //配置项,未实现 
37   var CFG = { 
38     POLL_INTERVAL: 50, 
39     MAX_TIME: 10 
40   }; 
41    
42   var head = document.head || document.getElementsByTagName('head')[0]; 
43   var styleSheets = document.styleSheets 
44   var env = getEnv(); //获取用户代理信息,为浏览器差异化加载提供判断依据 
45   var queue = []; //CSS加载队列 
46   /* 
47     @格式1 queue队列内元素格式 
48     { 
49       urls: ['a.css', 'b.css', 'd.css'], 
50       callback: function(param){},  //urls里面所有CSS文件加载完成后的回调方法,可选 
51       obj: {age:24} //callback回调方法传入的实参 
52     } 
53    */ 
54    
55  
56   function indexOf(arr, ele){ 
57     var ret = -1; 
58     for(var i=0,len=arr.length; i<len; i++){ 
59       if(arr[i]==ele) ret = i; 
60     } 
61     return ret; 
62   }   
63  
64   /** 
65    * @private 
66    * @description 返回用户浏览器代理信息,为判断不同浏览器提供依据 
67    * @return {Object} 格式见内部代码 
68    */ 
69   function getEnv() { 
70     var ua = navigator.userAgent; 
71     var env = {}; 
72  
73     (env.webkit = /AppleWebKit\//.test(ua)) 
74       || (env.ie = /MSIE/.test(ua)) 
75       || (env.opera = /Opera/.test(ua)) 
76       || (env.gecko = /Gecko\//.test(ua)) 
77       || (env.unknown = true); 
78  
79     return env; 
80   } 
81  
82   /** 
83    * @private 
84    * @description gecko内核的浏览器轮询检测方法 
85    * 参考://www.zachleat.com/web/2010/07/29/load-css-dynamically/ 
86    * @param {HTMLElement} node style节点,node.nodeName == 'STYLE' 
87    * @param {Object} queueObj 见@格式1 
88    */ 
89   function pollGecko(node, queueObj) { 
90     try { 
91  
92       node.sheet.cssRules; 
93  
94     } catch (ex) { 
95  
96       node.pollCount++; 
97  
98       if (node.pollCount < 200) { 
99 
100         setTimeout(function () { 
101           pollGecko(node, queueObj); 
102         }, 50);
103 
104       } else {
105 
106         finishLoading(node.href, queueObj);  //用不用略做些延迟,防止神一样的渲染问题??
107       
108       }
109 
110       return;
111     }
112 
113     finishLoading(node.href, queueObj);
114   }
115 
116 
117   /**
118    * @private
119    * @description webkit内核的浏览器轮询检测方法
120    * @param {HTMLElement} node link节点,node.nodeName == 'LINK'
121    * @param {Object} queueObj 见@格式1
122    */
123   function pollWebKit(node, queueObj) {
124 
125     for(var i=styleSheets.length; i>0; i--){
126     
127        if(styleSheets[i-1].href===node.href){
128         finishLoading(node.href, queueObj);
129         return;
130       }
131     }
132 
133     node.pollCount++; //轮询次数加1
134 
135     if (node.pollCount < 200) {
136       setTimeout(function(){
137         pollWebKit(node, queueObj);
138       }, 50);
139     } else {
140       finishLoading(node.href, queueObj);
141     }
142   }
143 
144   function checkSucc(className, attr, value){
145     var div = document.createElement('div');
146     div.style.cssText += 'height:0; line-height:0; visibility:hidden;';
147     div.className = className;
148     document.body.appendChild(div);
149 
150     return getComputedStyle(div, attr)==value;
151   }
152 
153   /**
154    * @description 获取节点样式值——只能获取比较简单的样式的值,一些兼容性问题不是重点,在这里不做处理,有兴趣可以看下jquery源码
155    * @param {HTMLElement} node dom节点
156    * @param {String} attr 样式名字,如display、visibility等
157    */
158   function getComputedStyle(node, attr){
159     var getComputedStyle = window.getComputedStyle;
160     if(getComputedStyle){161       return getComputedStyle(node, null)[attr];
162     }else if(node.currentStyle){
163       return node.currentStyle[attr];
164     }else{
165       return node.style[attr];
166     }
167   }
168 
169   /**
170    * @private
171    * @description url对应的CSS文件加载完成时的回调(404也包括在内)
172    * @param {String} url CSS文件的url
173    * @param {Object} queueObj 见@格式1
174    */
175   function finishLoading(url, queueObj){
176       var index = indexOf(queueObj.urls, url);
177       queueObj.urls.splice(index, 1);
178 
179       if(!queueObj.urls.length){
180         queueObj.callback(queueObj.obj);
181 
182         index = indexOf(queue, queueObj);
183         queue.splice(index, 1);
184       }
185   }
186 
187   /**
188    * @description 加载CSS的方法
189    * @param {Array} urls 加载的CSS文件名队列
190    * @param {Function} [callback] CSS文件队列全部加载完的回调
191    * @param {Object} obj callback的参数
192    * @param {Object} context
193    * @return {Undefined}
194    */
195   function loadCSS(urls, callback, obj) {
196     var queueObj = {
197       urls: urls,
198       callback: callback,
199       obj: obj
200     }
201     queue.push(queueObj);
202     
203     var pendingUrls = queueObj.urls;
204     for (var i = 0, len = pendingUrls.length; i < len; ++i) {
205       
206       var url = pendingUrls[i];
207       var node ;
208       if(env.gecko){
209         node = document.createElement('style');
210       }else{
211         node = document.createElement('link');
212         node.rel = 'stylesheet';
213         node.href = url;
214       }
215       //node.setAttribute('charset', 'utf-8');  //设不设置有木有影响,持保留态度
216       
217       if (env.gecko || env.webkit) {  //老版本webkit、gecko不支持onload
218         
219         node.pollCount = 0;
220         queueObj.urls[i] = node.href; //轮询判断的时候用到,因为不同浏览器里面取到的node.href值会不一样,有的只有文件名,有的是完整文件名?(相对路径、绝对路径)          
221         
222         if (env.webkit) {  //之所以要用轮询,后面讨论,@TODO: 新版本的webkit已经支持onload、onerror,优化下?
223         
224           pollWebKit(node, queueObj);
225         
226         } else {
227           
228           node.innerHTML = '@import "' + url + '";';  //为什么这样做,猛点击这里://www.phpied.com/when-is-a-stylesheet-really-loaded/
229           pollGecko(node, queueObj);
230         }
231 
232       } else {
233         
234         node.onload = node.onerror = function(){
235           finishLoading(this.href, queueObj);
236         };
237       }
238 
239       head.appendChild(node);
240     }
241   }
242 
243   //---------------------- 对外接口!---------------------------
244   return {
245 
246     /**
247      * @description 加载CSS文件
248      * 考虑:成功回调,错误回调分开?
249      * @param {Array|String} urls 要加载的CSS文件的文件名(相对路径,或绝对路径),比如:'style.css', ['style.css', 'test.css']
250      * @param {Function} [callback] 可选:文件加载完成后的回调(成功;或失败,如404、500等)
251      * @param {Object} [obj] 可选:回调执行时传入的参数
252      */
253     load: function (urls, callback, obj) {
254       loadCSS([].concat(urls), callback || function(){}, obj || {});
255     }
256 
257   };
258 })();

本文由职坐标整理发布,欢迎关注职坐标WEB前端HTML/CSS频道,获取更多HTML/CSS知识!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程