19

一、挑战

原本的平台业务只在手机移动端上跑,所以日常开发的习惯都是不考虑(也不需要考虑)兼容性的问题。平时会使用很多在低级别浏览器(IE8+)无法运行的API和框架(React、reflux)。在某次合作方接入竞猜平台的需求中,怎么让应用在我们PC端上跑起来,便成了挑战,也是这篇文章的起点~

二、思路/解决

1、分析数据确定方向

首先确定主要攻坚的浏览器版本类型,于是跑到度娘那查了一下全国的浏览器占比数据:

clipboard.png

另外要了公司某游戏部门官网的数据:

clipboard.png

分析数据得出,chromeIE8IE9IE10IE11是我们的主要目标。

本次文章主要讲IE8IE9IE10IE11的兼容~ 其他版本太低的IE就不管了:D

2、观察确定记录现状

第二步,在还没做任何兼容措施的情况下,应用出现了以下问题:

  1. postMessage数据传递失效<传递e.data只支持字符串> —— IE9及以下

  2. console对象undefined —— (小部分IE9)及以下

  3. Array对象的isArray方法undefined —— IE8及以下

  4. Object.defineProperty 方法undefined —— IE8及以下

  5. addEventListener兼容性问题 —— (小部分IE9)及以下

  6. 操作dom无权限 —— IE9及以下

  7. ....

  8. ....

咋看一下,问题好像很多。但其实都是一些可以快速兼容的问题。

样式问题这里就不写啦, 重构同学自动背锅。:D

3、对比及确定解决方案

兼容方案方向是用shim/polyfill库来对低级浏览器各个缺失的API、对象做补全。

<[译]shim和polyfill有什么区别?>
http://www.cnblogs.com/ziyunfei/archive/2012/09/17/2688829.html

我这里列举了一些github上比较常见、靠谱的方案: <没时间一个一个写啊...>

clipboard.png

感谢github

1)ieBetter

2)es5-shim/es5-sham

  • 优点:多而全、可靠的shim

  • 缺点:console/addEventListener没做容错兼容,Object.defineProperty在某些特殊版本有可能会有问题,但是基本可用。

  • 这作者还有做es6shim,有兴趣的同学可以了解一下

  • 地址:https://github.com/es-shims/es5-shim

3)console-polyfill

4)json3

5)html5Shiv

  • html5shiv主要解决HTML5提出的新的元素(section,header,footer)不被IE6-9识别,这些新元素不能作为父节点包裹子元素,并且不能应用CSS样式。html5shiv就是为了解决这个问题存在的。

  • 地址:https://github.com/aFarkas/html5shiv

6)addEventListener-polyfill.js

7)ie8

8)dom4

===============================================================

经过各种测试<踩坑>/搭配/组合,得出下面这套比较可靠的方案:有问题欢迎交流...

//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兼容性文档视图

clipboard.png

登过国内网银页面的同学应该都知道,网银的页面一般不兼容高版本的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之后,开始遇到这么一个问题:

clipboard.png

直接看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的文档说明可以参考:

clipboard.png

<跟随 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);

但其实,React0.13.0版本的非压缩版是有做相关处理的(所以一开始我用非压缩版是可以跑起来的)不知道为何min版本却被压没了。超级大坑...

后来在0.13.2版本min下,已经修复了,遂升级了一下我们的React,这个陷阱就跨过去了~

这是折腾了我最久的坑...超级坑...

3、压缩算法导致的问题

clipboard.png

搞好了陷阱1、陷阱2之后,遇到了reflux罢工的问题。

定位后发现平台的压缩算法(普通压缩UglifyJS)。会让模块在IE8有兼容性问题。

大概看了源码,发现可能是混淆压缩之后的对象被覆盖实例化了。这里只是猜测,有兴趣的同学可以自己去研究一下。

单纯用普通压缩reflux就跑起来了~

4、innerHTML问题

重构同学做了一下关于IE8css hack

body{background:#000 \9;}

重构同学请注意~

- 修复手段

一个\不行就用两个\

body{background:#000 \\9;}

四、总结

clipboard.png

至此,应用已经能在IE8/9/10/11跑起来了。其中辛酸苦逼无法形容。

定位疑难杂症的时候,应当保持思路清晰,多做排除/置换/简化,来剥离出病因。

卡住了,要多深呼吸冷静下来。再或者去25楼运动一下,说不定有奇效。

如果有什么问题欢迎RTX联系~

后续会补全兼容后的业务数据提升~

五、附件

附件有一个简单的demo,欢迎大家下载使用。


LincWong
98 声望9 粉丝