React16和Antd如何在IE9环境下忍辱偷生

项目使用React 16,控件库用Antd,要求兼容到IE9,所以最近两周一直在搞IE9的兼容性问题。一个原因是因为Antd整体上还是支持IE9的,但是在某些细节地方的兼容性做的并不是很好,需要开发人员自己想办法。上一篇文章中遇到的Webpack4打包后在IE9中遇到的问题现在回头看看,只能说是开了一个“好“头。

IE9引发的血案-如何处理webpack打包后体积依然过大的css文件

按理说,在Webpack,Babel这些工具的帮助下,浏览器兼容性问题不应该成为一个block产品交付的瓶颈,但是这个问题的的确确发生了。凡事总有两面性,尽管处理类似问题很麻烦,但是也通过这个机会让我体会到了两件事,那就是打包工具能做什么不能做什么,浏览器特别是IE9能做什么不能做什么

以下是问题的汇总,有些是常见的,但是既然我遇到了也就写下来。

  • IE9不能支持FormData
  • IE9不能支持文件(File) 接口
  • IE9不能识别application/json
  • IE9不支持以e.target.value的方式取Dom组件的value值(Input, Select etc…)
  • IE9不支持很多CSS3特性,比如animation
  • IE9不支持H5 Input控件(如select, email etc..)
  • IE9不能完全解析体积大于250k的css文件
  • 在设置滚动条overflow的情况下,不断滚动会导致底部出现大片空白(chrome, firefox无此类问题)
  • IE9下React不支持BrowserRouter,支持HashRouter

IE9不能支持FormData和文件(File)接口

项目使用的组件库是Antd,Antd提供了一系列功能丰富的控件。是我们无需把页面控件包含到Form中,我们通过Redux来管理页面控件的状态,点击提交按钮时,通过FormData来构造“模拟表单“键值对进行异步提交。

submit = () => {
        let formData = new FormData();
        formData.append("type", this.state.type);
        ...
        formData.append("file", $("#file_upload")[0].files[0]);// 获取文件
        $.ajax({
            url: this.url,
            type: 'POST',
            data: formData,
            success: function (res) {
                ....
            },
            error: function (res) {
                ....
            }
        });
    };

代码中我们既使用了FormData,也调用了File接口,在IE9上妥妥的挂了。如果不用FormData,Ajax就无法提交文件内容,哪怕浏览器支持File接口。FormData作为一个协议,也不存在什么Polyfill(从百度到谷歌,的确是没搜到)。那么能做的也只能是用最原始的form表单提交方法了。最原始的表单提交的最大问题就是会刷新页面,这意味着待提交页面上由Redux保管的state全部会被冲掉,这显然是不行的,很多提交表单后的业务逻辑会无以为继。

废话不说了,直接上解决方法:

  • jquery-form: 这个库可以帮助我们将原生的html from提交过程ajax化。(通过源码可以得知本质上还是过将form表单的target指向隐藏的iframe来实现页面中表单的无刷新提交,由iframe的’load’事件callback来处理后续逻辑)
require('jquery-form');

componentDidMount() {
        // ajaxSubmit正是jquery-form的关键方法
        $("#btnSubmitWithFile").click(function () {
                $("#importDataForm").ajaxSubmit({
                    url: this.uploadUrl, 
                    type: "post", 
                    dataType: "json", 
                    success: function (res) {
                       ...
                    },
                    error: function (res) {
                        ...
                    }
                });
            };
    }
  • 为每个表单控件创建一个Hidden Input,value值绑定state。这样做的好处是我们不用去维护页面中的state,还是交与Redux去处理,我们只需绑定好终值就可以了。
<RadioGroup onChange={this.setType} 
    value{this.state.type}>
         <Radio value={1}>本地上传Radio>
         <Radio value={2}>HDFSRadio>
RadioGroup>
<Input type="hidden" name="type" value={this.state.type}/>

return <div className="data-view">
            <Form id="importDataForm" enctype="multipart/form-data"> 
                {AddFromDom}
                <Input type="button" style={{display: "none"}} id="btnSubmitWithFile" value=" 上传" />
            Form>
        div>

IE9不能识别application/json

这个引发的主要问题是,IE9如果收到content-type为application/json的response,因为无法识别,因此会把他当成一个待下载文件处理,从而导致app无法接收并处理这个response。

这个问题的解决方法就是在后台将response的content-type设置为text/plain。前端注意的就是会接收到string类型的数据,需要用JSON.parse(res)转化成数据格式。

IE9不支持以e.target.value的方式取Dom组件的value值

e.target.value是从IE10开始支持的,所幸IE9中有e.currentTarget.value还可以取得正确的值。

//common.js
getInputValue(e) {
    if (!e || !(e.target || e.currentTarget)) {
        return e;
    }
    return e.target.value !== undefined ? e.target.value : e.currentTarget.value;
}

//page.jsx
import common from '../../components/common/common';

getValueFromEvent = e => {
    return common.getInputValue(e);
}

render() {
      
          {this.props.form.getFieldDecorator('createProjectName', {
              initialValue: {this.initialValue},
              rules: nameRules,
              getValueFromEvent: this.getValueFromEvent
          })(
              
          )}
      
}
...

以上代码需要注意的是,我们项目中用的是antd的控件,而e.target.value的获取在控件源代码中,还好,antd的Form表单提供了一个option: getValueFromEvent,我们可以在这里修改input事件产生的event对象。

IE9不支持很多CSS3特性,比如animation

一些加载的动画效果无法展现,由于时间与性价比的关系,我们并没有做什么workaround。不会影响功能,不影响用户使用,放在那里也能提醒用户IE9该换啦!!

IE9不支持H5 Input控件(如select, email etc..)

这个没什么好说的,避开使用就行。

在设置滚动条overflow的情况下,不断滚动会导致底部出现大片空白(chrome, firefox无此类问题)

诡异的问题,最后的解决方法来自google,在设置overflow的地方加一个’min-height: 0%;’

IE9下React不支持BrowserRouter,支持HashRouter

这个原因也很简单,BrowserRouter底层需要调用H5中增加的history.pushstate等新函数。

history MDN

import {HashRouter as Router, Route, Switch, Redirect} from 'react-router-dom' ;

经过几天的奋战,IE9的兼容性问题基本解决了。一句话总结React 16在IE9中的使用体验就是:宝马拉破车!

你可能感兴趣的:(React,兼容性)