一、挑战
原本的平台业务只在手机移动端上跑,所以日常开发的习惯都是不考虑(也不需要考虑)兼容性的问题。平时会使用很多在低级别浏览器(IE8+
)无法运行的API和框架(React、reflux
)。在某次合作方接入竞猜平台的需求中,怎么让应用在我们PC端上跑起来,便成了挑战,也是这篇文章的起点~
二、思路/解决
1、分析数据确定方向
首先确定主要攻坚的浏览器版本类型,于是跑到度娘那查了一下全国的浏览器占比
数据:
另外要了公司某游戏部门官网的数据:
分析数据得出,chrome
、IE8
、IE9
、IE10
、IE11
是我们的主要目标。
本次文章主要讲
IE8
、IE9
、IE10
、IE11
的兼容~ 其他版本太低的IE就不管了:D
2、观察确定记录现状
第二步,在还没做任何兼容措施的情况下,应用出现了以下问题:
postMessage
数据传递失效<传递e.data只支持字符串>
—— IE9及以下console
对象undefined
—— (小部分IE9)及以下Array
对象的isArray
方法undefined
—— IE8及以下Object.defineProperty
方法undefined
—— IE8及以下addEventListener
兼容性问题 —— (小部分IE9)及以下操作
dom
无权限 —— IE9及以下....
....
咋看一下,问题好像很多。但其实都是一些可以快速兼容的问题。
样式问题这里就不写啦, 重构同学自动背锅。
:D
3、对比及确定解决方案
兼容方案方向是用shim/polyfill库
来对低级浏览器各个缺失的API、对象做补全。
<[译]shim和polyfill有什么区别?>
http://www.cnblogs.com/ziyunfei/archive/2012/09/17/2688829.html
我这里列举了一些github
上比较常见、靠谱的方案: <没时间一个一个写啊...>
感谢github
1)ieBetter
优点:小而精的polyfill库
缺点:
console、Object.defineProperty
都没做处理。
2)es5-shim/es5-sham
优点:多而全、可靠的
shim
库缺点:
console/addEventListener
没做容错兼容,Object.defineProperty
在某些特殊版本有可能会有问题,但是基本可用。这作者还有做
es6
的shim
,有兴趣的同学可以了解一下
3)console-polyfill
简单的
console
兼容库~
4)json3
简单的
json
兼容库~
5)html5Shiv
html5shiv
主要解决HTML5提出的新的元素(section,header,footer)
不被IE6-9识别,这些新元素不能作为父节点包裹子元素,并且不能应用CSS样式。html5shiv
就是为了解决这个问题存在的。
6)addEventListener-polyfill.js
简单的
addEventListener
兼容库~
7)ie8
一个
IE8
的shim
库
8)dom4
让
IE8
获得dom level4
的能力
===============================================================
经过各种测试<踩坑>
/搭配/组合,得出下面这套比较可靠的方案:有问题欢迎交流...
//es5-shim + es5-sham + console-polyfill + json3 + html5Shiv + addEventListener-polyfill.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.7/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.7/es5-sham.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://gist.githubusercontent.com/eirikbacker/2864711/raw/dcc32b15ea79f8f364ca1707f81ec74a15fa25db/addEventListener-polyfill.js"></script>
//最后一个addEventListener-polyfill.js是直接github Raw下来的,建议自己保存
安利:https://cdnjs.com/ 是个好东西,搜github一些dist文件很方便,而且不用翻墙
三、陷阱/深坑
在引入shim
库之后,还踩了挺多莫名其妙的陷阱,下面我一个一个列举出来:
1、IE兼容性文档视图
登过国内网银页面的同学应该都知道,网银的页面一般不兼容高版本的IE,所以IE下有兼容性视图
的选项。对于我们来说,有可能会有IE11
的用户跑在IE7
的模式下面。
- 修复手段
这个陷阱可以通过设置meta
来解决:
<meta http-equiv="X-UA-Compatible" content="IE=edge">
有兴趣的同学可以通过阅读下方文章,了解这代码的含义:
<定义文档兼容性>
https://msdn.microsoft.com/zh-cn/library/cc288325
<使用X-UA-Compatible来设置IE浏览器兼容模式>
http://www.cnblogs.com/nidilzhang/archive/2010/01/09/1642887.html
2、特定版本React的兼容性问题
处理完陷阱1
之后,开始遇到这么一个问题:
直接看error
信息,应该是对一个undefined
对象引用了length
报的错。
为了查明原因,跟进React
源码(0.13.0
版本的压缩版源码)看 ,发现是IE8
下的firstChild.data undefined
了。代码片段如下:
e.innerHTML = "" + t;
var n = e.firstChild;
1 === n.data.length ? e.removeChild(n) : n.deleteData(0, 1);
在IE8
下,e.firstChild
是一个null
对象。所以会导致那样的报错,关于这个bug
的文档说明可以参考:
<跟随 Web 标准探究DOM>
http://www.cnblogs.com/joyeecheung/p/4168521.html
< Document Object Model FAQ >
http://www.cnblogs.com/joyeecheung/p/4168521.html
- 修复手段
修复手法是在设置innerHtml
的时候,前置一个bom
头\uFEFF
。
e.innerHTML = "\uFEFF" + t;
var n = e.firstChild;
1 === n.data.length ? e.removeChild(n) : n.deleteData(0, 1);
但其实,React
的0.13.0
版本的非压缩版是有做相关处理的(所以一开始我用非压缩版是可以跑起来的)不知道为何min版本却被压没了。超级大坑...
后来在0.13.2
版本min下,已经修复了,遂升级了一下我们的React
,这个陷阱就跨过去了~
这是折腾了我最久的坑...超级坑...
3、压缩算法导致的问题
搞好了陷阱1、陷阱2之后,遇到了reflux
罢工的问题。
定位后发现平台的压缩算法(普通压缩和UglifyJS
)。会让模块在IE8
有兼容性问题。
大概看了源码,发现可能是混淆压缩之后的对象被覆盖实例化了。这里只是猜测,有兴趣的同学可以自己去研究一下。
单纯用普通压缩,reflux
就跑起来了~
4、innerHTML问题
重构同学做了一下关于IE8
的css hack:
body{background:#000 \9;}
重构同学请注意~
- 修复手段
一个\
不行就用两个\
。
body{background:#000 \\9;}
四、总结
至此,应用已经能在IE8/9/10/11
跑起来了。其中辛酸苦逼无法形容。
定位疑难杂症的时候,应当保持思路清晰,多做排除/置换/简化
,来剥离出病因。
卡住了,要多深呼吸冷静下来。再或者去25楼运动一下,说不定有奇效。
如果有什么问题欢迎RTX联系~
后续会补全兼容后的
业务数据提升
~
五、附件
附件有一个简单的demo,欢迎大家下载使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。