以前对浏览器兼容性问题只是大概知道一些点,没想到这次真正着手去做的时候,还是碰到了很多问题。刚开始的时候一边解决问题,一边想着:用 IE8 的都是神经病,到后来,我发现完了,I LOVE IE。

0x00 起源

在这次做小蜜 PC 版的时候,由于早于 PC 版,无线版已经重新设计了全新版,做了很多架构上的优化调整。所以在做的时候把无线版的前端架构拿了过来,主要的考虑就是品牌和功能保持跟无线版统一的同时,技术上也可相互支持以及组件复用。

无线版技术上主要采用 ES6 + Webpack + Babel 的方式,由于项目的独特性和特殊需求,并没有使用任何框架,只引入 zepto 作为一个标准支撑库。

而 PC 版的架构跟无线版基本保持一致,主要是把 zepto 换成了 jQuery。

下面是一些基本的开发依赖:

{"devDependencies": {"babel-core": "~6.3.15","babel-loader": "~6.2.0", "babel-preset-es2015": "~6.3.13", "babel-preset-stage-0": "~6.3.13", "babel-runtime": "~6.3.13", "extract-text-webpack-plugin": "~0.9.1", "less-loader": "~2.2.1", "nunjucks-loader": "~1.0.7", "style-loader": "~0.10.2", "webpack": "~1.12.9", "webpack-dev-server": "^1.10.1" } }

0x01 polyfill

由于 Babel 默认只转换转各种 ES2015 语法,而不转换新的 API,比如 Promise,以及 Object.assign、Array.from 这些新方法,这时我们需要提供一些 ployfill 来模拟出这样一个提供原生支持功能的浏览器环境。

主要有两种方式:babel-runtime 和 babel-polyfill

babel-runtime

babel-runtime 的作用是模拟 ES2015 环境,包含各种分散的 polyfill 模块,我们可以在自己的模块里单独引入,比如 promise:

import 'babel-runtime/core-js/promise'

它们不会在全局环境添加未实现的方法,只是这样手动引用每个 polyfill 会非常低效,我们可以借助 Runtime transform 插件来自动化处理这一切。

首先使用 npm 安装:

npm install babel-plugin-transform-runtime --save-dev

然后在 webpack 配置文件的 babel-loader 增加选项:

loader: ["babel-loader"],
query: {plugins: ["transform-runtime"],presets: ['es2015', 'stage-0'] }

babel-polyfill

而 babel-polyfill 是针对全局环境的,引入它浏览器就好像具备了规范里定义的完整的特性,一旦引入,就会跑一个 babel-polyfill 实例。用法如下:

1.安装 babel-polyfill

npm install babel-polyfill --save

2.在入口文件中引用:

import 'babel-polyfill'

小结

其实做到这些,在大部分浏览器就可以正常跑了,但我们做的是一个用户环境很不确定的产品,对一些年代久远但又不容忽视的运行环境,比如 IE8,我们做的还不够。

接下来将开始讲述我们在兼容性方面遇到的一些问题,和解决方法。

0x02 开始在 IE8 运行

最开始做的时候并没有针对 IE 做一些兼容性方面的处理,结果在 IE8 上一跑一堆问题。

第一步,我们把 jQuery 换成 1.12.1 ,因为 2.X 已经不再支持 IE8。

但并没有像我们想象中的那样,只是简单换一下 jQuery 版本就可以正常运行了。

0x03 default or catch

这是遇到的第一个问题。在兼容性测试过程中,对下面的代码:

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

或者这种:

module.exports = _main2.default;

在 IE8 下会直接报”缺少标识符、字符串或数字”的错。

我们得在对象的属性上加 '' 才可以。就像下面这样:

function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { ‘default’: obj }; } module.exports = _main2['default'];

至于原因,并不是 IE8 下对象的属性必须得加 '' 才行,而是 default 的问题,作为一个关键字,同样的问题还包括 catch

这两种情况,可以通过使用 transform-es3-property-literals 和 transform-es3-member-expression-literals 这两个插件搞定。

总之,在平时写代码的时候避免使用关键字,或者保留字作为对象的属性值,尤其是在习惯不加引号的情况下。相关讨论:Allow reserved words for properties

0x04 es5-shim、es5-sham

为了兼容像 IE8 这样的老版本浏览器,我们引入 es5-shim 作为 polyfill。

但在遇到 Object.defineProperty 仍提示 "对象不支持此操作"

As currently implemented, the Object.defineProperty shim will not install on IE8 because IE8 already has such a method. However, the built-in IE8 method only works when applied to DOM objects.

其实 es5-shim 明确说明,这个方法的 polyfill 在 IE8 会失败,因为 IE8 已经有个同名的方法,但只是用于 DOM 对象。

同样的问题还包括 Object.create,上述问题可以再引入 es5-sham 解决.

0x05 addEventListener

项目中有部分代码直接使用 addEventListener 这个 API,但在 IE8 下的事件绑定并不是这个方法。

这个问题很容易解决,也无需去写额外的 polyfill。我们已经把 jQuery 换成 1.x,所以只需把代码中 addEventListener 换成 jQuery的写法就 Okay 了。

jQuery 其实为我们封装了很多 API,并做了很多兼容性的封装,类似的只要使用封装好的就可以了。

0x06 无法获取未定义或 null 引用的属性

这个问题是在特定场景下【转人工】出现的,出现问题的不是 IE8,而是 IE9 和 IE10。

原因是 ocs 实例创建失败,因为没有调用父类的构造函数。

通过安装 transform-es2015-classes 和 transform-proto-to-assign 解决。

在配置项加上这两个插件的配置:

{"plugins": [["transform-es2015-classes", { "loose": true }],"transform-proto-to-assign" ] }

0x07 postMessage

虽然 postMessage 是 HTML5 的特性,但 IE8 和 Firefox3 很早就实现了这个 API,当然,跟后来的标准并不一致。这其实也不能怪 IE8。

The postMessage method is supported in Internet Explorer from version 8, Firefox from version 3 and Opera from version 9.5.

我们可能会这样去使用:

parent.postMessage({success: 'ok', name: ‘mirreal’}, ‘*’);

但是为了兼容 IE8,我们得转成字符串:

parent.postMessage(JSON.stringify({success: 'ok', name: "mirreal"}), ‘*’);

另外一个需要注意的点是:在 IE8 下 window.postMessage 是同步的。

window.postMessage is syncronouse in IE 8

var syncronouse = true;
window.onmessage = function () { console.log(syncronouse); // 在 IE8 下会在控制台打印 true }; window.postMessage('test', '*'); syncronouse = false;

0x08 IE8/IE9 的控制台

遇到一个奇怪的问题,在刚开始遇到的时候(其实搞清楚原因,好像也挺正常的),小蜜在 IE8 IE9 无法加载。在 IE8 那个古老浏览器的左下角,好像也是唯一会在页面提示脚本错误的浏览器,提示 script error

第一反应就是应该又是某个函数在 IE 下不支持,准备打开控制台看看到底哪里报错,结果却什么事都没有了,页面竟然顺畅地加载出来了,这下该怎么调试好呢?

开始思考:什么东西是依赖控制台而存在的,到底会是什么呢。。。其实就是控制台本身。

原因就是我们在代码中添加了一些控制信息会打印在控制台,而 IE8/IE9 要开启 IE Dev Tools 才能使用 console 对象。

切忌把 IE8/9 想成 Chrome/Firefox,以为永远有 window.console 可用.终于,IE10 改邪归正,console 不再像段誉的六脉神剑时有时无。

console.log is there in IE8, but the console object isn't created until you open DevTools. Therefore, a call to console.log may result in an error, for example if it occurs on page load before you have a chance to open the dev tools.

但只要 IE8/9 还在一天,console 检查还是不能少的

事实上,IE8/9 从未死去,所以

就像这样:


if (window.console) {console.log('log here');
}

要是有一堆 console.logconsole.countconsole.errorconsole.timeconsole.profile,... 这样去写,那还不把人写到恶心死。

写个简单的 console polyfill 吧,检测是否存在 console,不存在可以常见一个同名的空方法达到不报错的目的。当然,生产环境的代码其实也不会有那么多奇奇怪怪的 console

0x09 定义文档兼容性

X-UA-Compatible 当初是针对 IE8 新加的一个配置。用于为 IE8 指定不同的页面渲染模式,比如使用 IE7 兼容模式,或者是采用最新的引擎。

现在基本也不需要前者的降级模式,更多的是写入 IE=edge 支持最新特性。而 chrome=1 则会激活 Google Chrome Frame,前提是你的 IE 安装过这个插件。

有什么用呢,当然有用,有些 API 是作为新特性存在于 IE8 中的,比如 JSON,不开启的话就用不了。

为什么要用 X-UA-Compatible?

在 IE8 刚推出的时候,很多网页由于重构的问题,无法适应较高级的浏览器,所以使用 X-UA-Compatible 强制 IE8 采用低版本方式渲染。

比如:使用下面这段代码后,开发者无需考虑网页是否兼容 IE8 浏览器,只要确保网页在 IE6、IE7 下的表现就可以了。

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

而这段代码:

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

IE=edge 告诉 IE 使用最新的引擎渲染网页,chrome=1 则可以激活 Chrome Frame[1]。

0x0a 条件注释 or 条件编译

最后说说 IE 的条件注释,用法如下:

!    [if !IE]    The NOT operator. This is placed immediately in front of the feature, operator, or subexpression to reverse the Boolean meaning of the expression. lt [if lt IE 5.5] The less-than operator. Returns true if the first argument is less than the second argument. lte [if lte IE 6] The less-than or equal operator. Returns true if the first argument is less than or equal to the second argument. gt [if gt IE 5] The greater-than operator. Returns true if the first argument is greater than the second argument. gte [if gte IE 7] The greater-than or equal operator. Returns true if the first argument is greater than or equal to the second argument. ( ) [if !(IE 7)] Subexpression operators. Used in conjunction with boolean operators to create more complex expressions. & [if (gt IE 5)&(lt IE 7)] The AND operator. Returns true if all subexpressions evaluate to true | [if (IE 6)|(IE 7)] The OR operator. Returns true if any of the subexpressions evaluates to true. 

另外一个类似的东西是在 Javascript 中的条件编译(conditional compilation)。我们可以使用这段简单的代码来做浏览器嗅探:

var isIE = /*@cc_on!@*/false

在其他浏览器中,false 前的被视为注释,而在 IE 中,/*@cc_on .... @*/ 之间的部分可以被 IE 识别并作为程序执行,同时启用 IE 的条件编译。

常用变量如下:

* @_win32 如果在 Win32 系统上运行,则为 true。
* @_win16 如果在 Win16 系统上运行,则为 true。
* @_mac 如果在 Apple Macintosh 系统上运行,则为 true。
* @_alpha 如果在 DEC Alpha 处理器上运行,则为 true。
* @_x86 如果在 Intel 处理器上运行,则为 true。 * @_mc680x0 如果在 Motorola 680x0 处理器上运行,则为 true。 * @_PowerPC 如果在 Motorola PowerPC 处理器上运行,则为 true。 * @_jscript 始终为 true。 * @_jscript_build 包含 JavaScript 脚本引擎的生成号。 * @_jscript_version 包含 major.minor 格式的 JavaScript 版本号。

Internet Explorer 11 之前的所有版本的 Internet Explorer 都支持条件编译。 从 Internet Explorer 11 标准模式开始,Windows 8.x 应用商店应用不支持条件编译。

之前一直在做移动端的开发,没想到做 PC 端也会遇到这么多的兼容性问题。不同于移动端设备的繁杂和不确定性,PC 版的兼容更侧重于对特定浏览器的特性的了解,相比而言更为明确,而非因为某一款手机的诡异表现。

参考文档

  • Allow reserved words for properties

  • IE8 defineProperty/getOwnPropertyDescriptor clash with shim

  • Runtime transform

  • babel-plugin-transform-runtime definitions

  • super() not calling parent's constructor on IE9

  • postMessage method (window) Javascript

  • 使用 F12 工具控制台查看错误和状态.aspx)

  • 定义文档兼容性.aspx)

  • 条件编译 (JavaScript).aspx)

转载于:https://www.cnblogs.com/godghdai/p/7657695.html

使用 ES6 的浏览器兼容性问题相关推荐

  1. ES5、ES6的浏览器兼容性

    从https://www.caniuse.com上面可以查询到,ES的兼容性概览. 下面就主要浏览器进行说明:  IE:可以看到IE6,IE7是完全不支持的.而IE8是只支持一些内容,参考引用4,IE ...

  2. 减少浏览器兼容性问题

    做为一个前端工程师,不少时间都在处理浏览器兼容性问题.本文对如何减少浏览器兼容性问题的方法做了些总结. 确定运行环境 在开发前,我们要确定页面的运行环境:要兼容哪些浏览器,以及哪些屏幕分辨率. 如果我 ...

  3. vue es6转es5 保证浏览器兼容性

    vue cli es6转es5 保证浏览器兼容性 安装 在根目录下创建.babelrc文件 IE报vuex requires a Promise polyfill in this browser问题解 ...

  4. 浏览器兼容性篇-vue篇-ES6转ES5

    在 vue 项目中,ie浏览器识别ES5写法的javascript代码,而IE浏览器不支持,所以需要借助插件 babel-polyfill ,解决方案如下: vue-cli2下 解决浏览器兼容性问题 ...

  5. web前端关于浏览器兼容性

    web前端关于浏览器兼容性 所谓的浏览器兼容性问题,是指因为不同的浏览器对同一段代码有不同的解析,造成页面显示效果不统一的情况.在大多数情况下,我们的需求是,无论用户用什么浏览器来查看我们的网站或者登 ...

  6. 关于vue-cli3的浏览器兼容性

    这里先给出几个链接: 1.Vue-cli浏览器兼容性:https://cli.vuejs.org/guide/browser-compatibility.html#usebuiltins-usage ...

  7. 浏览器兼容性常见问题

    CSS 1. 不同浏览器的标签默认的padding和margin不同 通配符 *{margin:0;padding:0;} 2. IE盒模型:margin.content(包含padding.bord ...

  8. 关于Vite项目打包后浏览器兼容性问题的解决方案

    一.问题描述 vite+vue3项目开发完以后,你会发现打包后的项目运行在新版浏览器可以正常显示,但运行在一些版本比较老的浏览器如 Chrome < 23.Firefox < 21和IE等 ...

  9. html 引入js 兼容,JS跨浏览器兼容性解决思路及方案汇总,常见JS兼容性知识点汇总...

    上篇文章我们介绍了,处理CSS浏览器兼容性的4个解决方案:浏览器CSS样式初始化.浏览器私有属性,CSS hack语法和自动化插件,有兴趣的可以看看,链接放到本文结尾 本文主要介绍JS的跨浏览器兼容性 ...

最新文章

  1. python中re_Python中re(正则表达式)模块学习
  2. Java(发布/订阅模式)
  3. Type Casting
  4. Bash脚本教程之循环
  5. 信息学奥赛C++语言:趣味整数2(亲密数)
  6. mysql索引数据结构图解_MySQL索引底层结构与实现原理
  7. CSS列表样式(源码示例)
  8. Matlab计算轮廓内切圆
  9. teamviewer 服务器系统,远程支持服务器搭建teamviewer
  10. 天龙八部荣耀版体验服服务器未响应,《天龙八部荣耀版》体验服评测:用竖版画面重新诠释天龙江湖...
  11. 6种方法轻松将PDF转换为Word文档,办公必备!
  12. 温敏壳聚糖水凝胶细胞因子复合支架/季铵盐壳聚糖水凝胶三维支架复合GNDF载间充质干细胞的制备
  13. win7、win10系统双屏显示任务栏
  14. time_t和SYSTEMTIME之间的相互转换 【转】
  15. 【游戏外挂、修改器、辅助研究1】认识外挂
  16. 酷我音乐盒在听一遍就自己默认下载…
  17. 为什么同门硕士进了BAT拿高工资,而博士却要挤破头进985高校?
  18. 爬虫实践:爬取搜狗图片
  19. C语言对浮点数变量小数点后两位的四舍五入
  20. Java进阶(五十五)-Java Lambda表达式入门

热门文章

  1. Dubbo的远程回调
  2. install python-tk_No module named _tkinter, please install the python-tk package 解决方法总结
  3. Ubantu install jdk
  4. java删除指定目录下文件_Java中循环删除指定目录下的文件
  5. 大厂面试算法系列-如何实现链表的逆序(一)-原地逆序
  6. OSSemPend()--等待一个信号量
  7. 国外的老师是怎么教Golang的?
  8. 如何扩展Laravel Auth来满足项目需求
  9. Docker容器虚拟化技术---Docker运维管理(Docker Compose)4
  10. Spring Security中HttpSecurity常用方法及说明