17
2013
09

用Javascript来处理CSS未加载或加载出错

CSS作为一个网页的灵魂,如果CSS加载出错我们可能看到的是一个面目全非的网页,没有样式,一切HTML标签都露除了原来的面目。什么情况下样式会失效呢?

  1. CSS文件加载失败(可能因为网络阻塞,或其他原因)

  2. CSS文件不存在

  3. CSS文件加载成功,而因为某种阻塞的原因而没有渲染(某种情况下JavaScript阻塞,这就是为什么我们要把CSS加载放head,而推从把JavaScript放最后加载的原因之一),或则加载的CSS是缓存中的文件也就是状态码304,也就是加载的不是最新的文件。

对于第二种情况,我们真没啥办法,文件都没有,我们先找到CSS文件了,对与其他两个问题,我们可以想到以下方案。

CSS文件加载失败的情况和CSS文件加载成功,但没有渲染的情况

其实解决这个问题,只要直接重新加载一次就好了。如下代码:

node.href = node.href + '?v=' + Math.random();

原理很简单,就是改变link节点的href属性,加入随机编码是保证加载的CSS为最新的。

处理问题的关键不在重新加载CSS文件,而在检测是否加载失败或未渲染

直接上代码

	function UnloadCompletelyCssHandler() {

		var reloadCssFile = function(node) {
			node.href = node.href + '?v=' + Math.random();
		};

		var clearFileCache = function(url, done, fail) {
			$.ajax({
				url: url,
				headers: {
					'If-Modified-Since': 'Thu, 01 Jan 1970 00:00:00 GMT',
					'Cache-Control': 'no-cache'
				}
			}).done(function(responseText, textStatus, jqXhr) {
				(jqXhr.status === 200 ? done : fail)();
			}).fail(fail);
		};

		var checkCrossDomain = function(url) {
			var proIdx = url.indexOf('//');
			var protocol = url.substring(0, proIdx);
			var hostname = url.substring(proIdx + 2, url.indexOf('/', proIdx + 2)),
				locationHostName;

			hostname = hostname.split(':')[0];
			locationHostName = location.hostname.split(':')[0];

			return (protocol !== location.protocol || hostname !== locationHostName);
		};

		this.getUnloadCompletelyNodes = function() {
			var styleSheetList = document.styleSheets,
				unloadCompletelyArr = [];

			for (var i = 0, len = styleSheetList.length; i < len; i++) {
				var styleSheet = styleSheetList[i],
					node = styleSheet.ownerNode || styleSheet.owningElement,
					rules = styleSheet.cssRules || styleSheet.rules;

				if (node.nodeName === 'LINK' && !styleSheet.disabled) {
					try {
						if (rules.length <= 0) {
							unloadCompletelyArr.push(node);
						}
					} catch (ex) {
						//本方法不处理跨域请求.
						if (!checkCrossDomain(styleSheet.href)) {
							unloadCompletelyArr.push(node);
						}
					}
				}
			}

			return unloadCompletelyArr;
		};

		this.reloadCssFiles = function(nodes, failedCallback) {
			var unloadCount = nodes.length,
				loadCount = 0,
				failCount = 0;

			for (var i = 0; i < unloadCount; i++) {
				var node = nodes[i];

				reloadCssFile(node);
				node.onload = node.onreadystatechange = function() {
					if (!this.readyState || this.readyState === "complete" || this.readyState=='loaded') {
						node.onload = node.onreadystatechange = null; //防止IE内存泄漏
						loadCount++;
					}
				};
				node.onerror = function(){
					failCount++;
					if (loadCount + failCount == unloadCount && failCount > 0) {
						failedCallback();
					}
				};
			}
		};

		this.clearCacheAndReloadCssFiles = function(nodes, failedCallback) {
			var unloadCount = nodes.length,
				loadCount = 0,
				failCount = 0;

			for (var i = 0; i < unloadCount; i++) {
				var node = nodes[i];
				clearCache(node.href, function() {
					loadCount++;
					reloadCssFile(node);
				}, function() {
					failCount++

					if (loadCount + failCount == unloadCount && failCount > 0) {
						failedCallback();
					}
				});
			}
		};

	}

调用代码:

var cssHandler = new UnloadCompletelyCssHandler();
var unloadCompletelyCssNodes = cssHandler.getUnloadCompletelyNodes();
if (unloadCompletelyCssNodes.length > 0) {
	cssHandler.reloadCssFiles(unloadCompletelyCssNodes, function() {
		alert('also load file');
	});
}


« 上一篇下一篇 »

评论列表:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。