React 16 兼容 IE9+

3,305 阅读4分钟

小编拿到需求。就是一把梭。然而,后来说要把 React 16 的项目兼容到 IE9+,好吧,继续梭。 以下是我在兼容 IE 时遇到的问题


1:浏览器上打开兼容模式是是白屏

拿到项目时。在一些浏览器上打开 IE 模式是是白屏的。好吧。这个问题其实很好解决,Babel 了解一下。

npm install --save @babel/polyfill

在入口文件上的第一行加上 import '@babel/polyfill'

IE11 终于有东西出来了。舒服舒服

2:Map 和 Set 异常

npm install core-js

入口文件顶部加上

import 'core-js/es6/map'
import 'core-js/es6/set'

3:Promise 报错

npm install --save @babel/polyfill

在入口文件上的第一行加上 import '@babel/polyfill'

是的,解法跟问题 1 一样。


在 浏览器中的 IE 兼容模式调整至 IE9,看似一切正常,但是测试哥们说 IE9 浏览器不行啊。所以我自己用虚拟机搞了个 Win7 调试,emmmm……还真不行…… 在 Win7 的 IE9 浏览器上 报了如下错误

4:无法获取属性 responseText 的值,对象为 null 或未定义

小编在浏览器 用 IE9 兼容模式 疯狂刷新,居然也出现这个报错了,但是页面是正常显示的,这 bug 居然是偶现的。

原项目的请求库采用的是 reqwest 在 npm 上 reqwest 介绍中提到兼容 IE6+,项目在请求的写法采用的是 async / await ,reqwest 说兼容到 IE6+,难道是 babel 的锅?

直到我在浏览器点开报错文件,并整理。看到是 reqwest 的 API success 方法 中的参数报错

还好请求的接口不是很多,所以我尝试的更换了请求库 axios

    reqwest({
        method:get,
        url:url,
        data:{data:data},
        crossOrigin: true, // cors跨域,服务端与客户端存在cookie等数据凭证交互时需要设置
        withCredentials: true
    })
    // 相对应 Axios
    axios.get(url,{data:data},{
        crossDomain:true,
        withCredentials: true  //  表示跨域请求时是否需要使用凭证
    })

IE兼容模式 -> done!
IE9 浏览器 -> 这次终于有部分内容渲染出来了!

5:IE9 上的跨域请求

延续上个问题,为什么是部分内容出来,控制台此时显示着“拒绝访问”, google / 百度一下吧
有文章提到是 promise 的兼容问题也会提示“拒绝访问”。但是这个问题是跨域才会出现的。自然排除。


问题原因: IE9 XMLHttpRequest 不支持 CORS

fetch 的 polyfill 采用了 XMLHttpRequest 实现, 但是在 IE9 下面, XMLHttpRequest 是不支持跨域请求的. IE10 的 XMLHttpRequest 支持跨域, 而 IE8, IE9 需要使用 XDomainRequest 来实现跨域.

那就用 XDomainRequest 实现异步请求, 代码:

functionfetchIe9(url, options = {}) => {
	if (window.XDomainRequest) {
		// https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest
		// only support GET and POST method
		// request and response content type should be JSON
		// without response status code
		returnnewPromise((resolve, reject) => {
			constmethod = options.method || 'GET';
			consttimeout = options.timeout || 30000;
			letdata = options.body || options.params || {};
			if (datainstanceofObject) {
				data = JSON.stringify(data);
			}
			constXDR = newXDomainRequest();
			XDR.open(method, url);
			XDR.timeout = timeout;
			XDR.onload = () => {
				try {
					constjson = JSON.parse(XDR.responseText);
					returnresolve(json.data);
				} catch (e) {
					reject(e);
				}
				returnreject({});
			};
			XDR.ontimeout = () => reject('XDomainRequest timeout');
			XDR.onerror = () => reject('XDomainRequest error');
			XDR.send(data);
		});
	} else {
		// native fetch or polyfill fetch(XMLHttpRequest)
		// fetch...
	}
}

需要注意的是: XDomainRequest 只支持 GET 和 POST mehtod XDomainRequest 不支持带 cookie XDomainRequest 不能设置 responseType, 通信双方需要约定数据格式 XDomainRequest 的响应没有 response status code

题外话: whatwg-fetch 一直采用 XMLHttpRequest 来做 polyfill, whatwg-fetch1.0+ 不支持 IE9, 并不是因为没有采用 XDomainRequest, 而是因为 IE9 的状态码不符合 fetch 规范, 而 polyfill 的目标是 polyfill 规范, 而不是做兼容.

来自链接 cloud.tencent.com/developer/n…

如果是 JQ 使用的话。推荐 jQuery-ajaxTransport-XDomainRequest,CDN 引入即可,请求方式不变,十分方便

6:点击内容 跳转 无反应 (非 a 链接)

点击跳转的大概逻辑

if(条件1){
    console.log(123);
    window.location.href = '链接1'
}else{
    window.location.href = '链接2'
}

解决方案:
1:需要调出控制台 才可以跳转 把console.log 打印去掉即可
2:定时器,将跳转逻辑异步出来 || 阻止冒泡

总结

一步步解bug的过程是让人奔溃的,但是在需求完成时,成就感真的不是一点点。JQ 在 IE 兼容方面,不得不承认他的优势。时代是在进步的,JQ 或许会随着 IE 的没落而渐渐没有优势,但对于现在来说。IE 想完全退出舞台,可能还言之过早。