前言
本文主要研究的是angularJS框架在IE8下兼容性的问题,分析了导致angularjs框架在ie8下不能使用的各个因素,并逐个分析、解决它,并提出angularjs在IE8下统一的解决方案。
本文目的
1.提供angularJS在IE8下兼容性的统一解决方案。
兼容性说明
编号 | 标题名称 | 描述 |
1 | angularJS | angularJs从1.3版本开始已经放弃对IE8的支持 |
2 | jquery | Jquery 1.9是最后支持IE6/7/8的版本,且jquery1.9中包含很多html5方法 |
3 | bootstrap | Bootstrap css3的特性完全不支持ie8,且bootstrap3需要jquery版本至少为1.9.1 |
4 | Html5 | IE8不支持H5的特性和方法 |
5 | ECMAScript | IE8仅支持一点ECMAScript5,ECMAScript6完全不支持 |
解决思路
根据上面表格中提出的兼容性问题,可以概括解决angularjs在ie8下兼容性问题的思路如下:
1.降低版本 : 使用angularjs-1.2.30,使用jquery-1.9.1,使用bootstrap3.3
2.加入补丁 : 加入ECMASCRIPT5补丁让IE8支持html5的特性与方法
3.手写补丁 : es5补丁中没有或者无效的方法,需要手写补丁去支持
4.修改源码: 修改控件源码,替换,修改IE8不支持的方法,这是一个复杂、工程量大的问题,只能做到具体问题具体分析。
运用思路1、2可以在IE8中搭建起angularjs前端MVC模式 ,运用思路3、4可以把不支持IE8的控件手动改造成支持IE8的控件,思路全部应用能够搭建支持IE8的angularjs前端框架!
解决版本问题
降低jquery到1.9.1版本,angularjs至少到1.2.30版本,bootstrap到3.3版本,这只是前提,此时并不能搭建好angularjs MVC模式,可以使用ui-router,但是ui-router实现的样式依赖bootstrap3,而bootstrap3不支持IE8,样式全部失效,整个页面布局乱七八糟,要想搭建好angularjs MVC必须解决bootstrap的IE8兼容性问题!
解决Bootstrap兼容性问题
1.使用html5文档声明
<!DOCTYPE html>
2.加入meta标签
前者定义媒体查询,后者确定显示此网页的IE版本。
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
3.引入respond.js和html5.js
respond.js是用于媒体查询,html5shiv : html5.js是让不支持或不完全支持html5的浏览器“支持”html5标签,两者均需要到github中去下载,注:两者需要在head中加入,且要在jquery和bootstrap之前引入。
<script language="JavaScript" src="bower_components/bootstrap/html5shiv.js"></script>
<script language="JavaScript" src="bower_components/bootstrap/respond.js"></script>
完整代码
<!DOCTYPE html>
<html ng-controller="appCtrl">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta charset="UTF-8">
<script language="JavaScript" src="bower_components/bootstrap/html5shiv.js"></script>
<script language="JavaScript" src="bower_components/bootstrap/respond.js"></script>
</head>
<script language="JavaScript" src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
解决H5兼容性问题
经过上一步bootstrap的兼容性调整,现在我们已经可以让angular跑起来了!但仅仅这样是不够的,html5shiv.js只是让IE8支持h5的标签,我们还需让它支持H5的特性和方法,所以需要引入es5shim和es5sham,两者均需要在github下载,如下所示。
<script src="bower_components/es5-shim/es5-shim.js"></script>
<script src="bower_components/es5-shim/es5-sham.js"></script>
另外ie8不支持foreach,我们需要额外写补丁去修复它,代码如下。
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function forEach( callback, thisArg ) {
var T, k;
if ( this == null ) {
throw new TypeError("this is null or not defined" );
}
var O = Object(this);
var len = O.length >>> 0;
if ( typeof callback !== "function" ) {
throw new TypeError( callback +" is not a function" );
}
if ( arguments.length > 1 ) {
T = thisArg;
}
k = 0;
while( k < len ) {
var kValue;
if ( k in O ) {
kValue = O[ k ];
callback.call( T, kValue, k, O );
}
k++;
}
};
}
整合修复bootstrap完整代码如下,jquery和bootstrap一定要在之后引入.
至此angularjs在ie8下已经搭建成功了,现在我们要着手解决控件的问题,由于很多控件使用了不同的h5特性与方法,补丁不能够完全覆盖,我们要具体问题具体分析,这里以angular-ui-tree、ui-grid、ng-dialog、jquery-fileupload-angular为例。
其他细节:css上,bootstrap的col-sm、col-md无效,请使用col-xs系列 ,另外要额外修改bootstrap的from-control为
.form-control{
width:auto !important;
display:inline-block !important;
}
在指令的使用上不要把指定名称当做标签使用,因为采用了css3的东西,ie8是不识别的,这一点要额外注意
angular-ui-tree
在ie8下启动angularjs成功后,发现树控件已经挂了,分析原因发现是ie8不支持catch和finally的写法
修改为
问题解决
解决了try catch问题后 发现树不能拖拽了,分析原因发现
问题出在this.originalEvent这段代码上,this.originalEvent为鼠标事件,在ie9中才支持,ie8中无法支持,必须写补丁,方法太多,补丁无法写出,所以树的拖拽功能暂时放弃,之后用其他形式替代
Grid控件
在ie8下启动angularjs成功后,发现Grid已经挂了,分析原因发现Object.defineProperty出现了问题,原因在于在IE8下只支持对DOM元素定义property,无法对对象定义property
修改为:
问题解决。
ngDialog控件
在ie8下启动angularjs成功后,发现Grid已经挂了,分析原因发现
querySelectorAll的问题,那么首先要观察focusableElementSelector的值,发现
focusableElementSelector="a[href],area[href],input:not([disabled]),select:not([disabled]), textarea:not([disabled]),button:not([disabled]),iframe,object,embed,*[tabindex],*[contenteditable]"
仔细分析发现IE8中的querySelector不支持input:not[(disabled)]这类css3的写法,去掉这种形式,牺牲了控件的一点功能,修改后解决。
dialogEl.querySelectorAll("a[href],area[href],iframe,object,embed,*[tabindex],*[contenteditable]");
jquery-fileupload 控件
在ie8下启动angularjs成功后,发现fileupload控件已经挂了,分析原因发现
Ie8下不支持$applyAsync这个属性,$applyAsync为scope中的一个异步方法,跟他有同样作用的是$evalAsync,不同之处在于$evalAsync每次都会触发$digest循环,多了一些性能负担,但不影响控件的使用,把控件源码中所有$applyAsync修改为$evalAsync,问题解决。
最后,还要修改upload的后台
Application/json变为text/plain或text/html,这样返回的json信息IE才不会把它当做文件去下载。
总结
IE8属于旧时代的产物,被时代所淘汰已经是必然的趋势。然而,在实际工作中,由于业务和需求的限制我们有的时候不得不用IE8,处理它复杂的兼容性问题,angularjs是互联网时代的前端MVC框架,它与IE8配合就好比在奔腾4上玩LOL,就算可以运行,也会牺牲LOL的很多性能,本文虽然提出了一个IE8与angularjs配合的可行方案,但在实际工作中希望大家远离IE8,即使要用的话,相关的控件请使用纯jquery或javascript控件,新的控件多多少少都涉及到了H5,在IE8上多数是不可行的。