VUE项目中遇到的一些IE11兼容性问题及解决方案

4,201 阅读5分钟

原以为IE11下应该不会存在什么兼容问题,毕竟ie11也勉强算得上新时代的浏览器,但实际使用时,遇到的问题还不少!

问题1:打包后的代码中中出现了不识别的es6语法或其他新的js特性

范围:全局

image.png

解决方案:

首先查看报错的js文件,如果是 chunk-vendor 文件中的js语法错误,那么可以基本确定是由于依赖包中引入的代码为非es5代码引起的,由于线上代码为压缩后的代码,无法确定是哪个依赖包中使用ie不识别的代码,这时可以在本地使用此命令yarn build --mode=development,打包获取一份未经过压缩的代码,其中包含具体引入的node_modules里的包的路径信息,然后再对比ie中报错的文件进行关键字搜索确定具体的依赖包报错,确认过后,将依赖包名称加入到vue.config.js中的transpileDependencies选项即可。

如果是其他chunk文件或者main.js等报错,一般则是代码中使用到了ie中不支持的一些新的js特性,自行找到相关代码更改即可。

例如我司项目中已经发现的不兼容的一些依赖,已经发现的不兼容的依赖包如下:

    // vue.config.js
    ...
    transpileDependencies:["vue-echarts-v3", "view-design", "elasticsearch"]
    ...

view-design也就是iview@4.x版本,其本身是提供了es5的代码了,但因为项目中有单独引入iview中的emitter工具函数,所以需要经babel处理。另外,如果是按需引入 iview的话,也需要经过babel转译为es5代码。

问题2:get请求传递中文参数乱码

范围:全局

解决方案:

1). 对get的参数使用encodeURIComponent进行编码

2). 如果使用axios作为ajax请求,则把参数放入params中,而不是手动拼接,axios会自动编码

问题3:el-cascader在处于多选模式并且filterable为true时,会自动聚焦并弹出选择面板。

原因:在IE11下input的placeholder发生变化后会触发oninput事件(只要对input的placeholder设置就会触发,即便placeholder的值并没有发生变化)

范围:Element-UI中cascader组件

解决方案:

修改组件中的方法代码

import { Cascader } from 'element-ui';

const isIE = !isNaN(Number(document.documentMode));

if(isIE) {
  Cascader.methods.handleInput = function(val,event) {
  // 仅在有值输入的时候才弹出dropdown
    if(this.multiple && this.filterable && val) {
      !this.dropDownVisible && this.toggleDropDownVisible(true);
    }
    // 以下代码为el-cascader组件部分源码

    if (event && event.isComposing) return;
    if (val) {
      this.filterHandler();
    } else {
      this.filtering = false;
    }
  }
}
Vue.component(Cascader.name, Cascader);

问题4:el-cascader组件在多选模式下无法显示标签文字.

范围: Element-UI中Cascader组件

解决方案:将el-cascader下的el-tag样式由flex:1改为:flex: 1 1 auto;

问题5:flex布局下如果有position:absolute的元素,那么对这个绝对定位元素定位时,请不要依赖flex布局中的默认位置。

范围:全局

一个元素如果设置为position:absolute之后没有设置具体的定位位置,那么就会使用在原文档流中应该处于的位置,但IE中如果在Flex布局里将flex子项设置为绝对定位后,样式并未保持在原本所处的位置。

例:

    <div style="display:flex; align-items:center">
        <i style="position:absolute">
    </div>
    <!-- 如果i元素是一个绝对定位元素,并且没有设置具体定位,那么我们期待的表现应该是i元素处于垂直居中的一个位置,在chrome中表现是这样的,但在ie中是不处于居中位置的,所以最好还是给一个具体定位 -->

问题6:iview table组件开启拖拽排序功能在拖拽时会报错

原因:在IE中,拖放事件通过e.dataTransfer.setData存储数据时,设置的key只能是text或者url(大小写皆可),否则就会报错。而Table组件的拖拽通过e.dataTransfer.setData('index',index)保存索引导致报错

范围: IView库 Table组件

解决方案:在入口文件中引入iview组件库后手动修改组件中的方法,切记不要使用箭头函数,否则this指向错误。

    import iView from 'iview';
    iView.Table.components.tableBody.components.TableTr.methods.onDrag = function(e, index){
      e.dataTransfer.setData('text',index);
    };
    iView.Table.components.tableBody.components.TableTr.methods.onDrop = function(e, index){
      const dragIndex = e.dataTransfer.getData('text');
      this.$parent.$parent.dragAndDrop(dragIndex,index);
      e.preventDefault();
    }

问题7: IE浏览器会缓存网页中的发起的的ajax get请求的内容

原因:当请求方式是get方式时,IE浏览器会进行识别。如果该get请求的url是第一次请求的话,会请求服务器,从服务器中获取最新数据;如果该get请求的url不是第一次请求的话,那么该url就不会请求服务器,IE浏览器会直接从缓存中拿到上次该url获取的数据,从而会导致数据不同步

范围: 全局

解决方案(任选一种):

  1. 在get请求的url中增加随机标识,例如增加时间戳,一般是在axios的请求拦截器中进行操作,统一加上时间戳参数。

  2. 设置请求头'Cache-Control': 'no-cache'

   // 此请求头告知浏览器使用本地缓存前需要跟服务器验证
   const httpRequest = axios.create({
     headers: {
       'Cache-Control': 'no-cache'
     }
   })

问题8:IE不支持粘性定位,即position: sticky,请不要使用此种定位方式

问题9:NodeList在ie中不支持forEach方法

解决方案:NodeList本质为一个集合,是一个类数组结构,所以可以转为数组结构再使用相关数组api。

   const body = document.body;
   // ie下不支持此种方法
   body.childNodes.forEach(node => {...})
   // 转为数组结构后可安全使用
   const nodeArr = [].slice.call(body.childNodes);
   nodeArr.forEach(node => {...})

问题10:后行断言正则表达式无法被识别

范围:全局

解决方案:

什么是后行断言,即 /(?<=a)b/此种形式,此行正则的意思为 查找字符前紧跟a字符的b字符,由于ie无法支持此种正则,需要改造,可将其改造为普通捕获正则,如将上述正则改为/a(b)/,同时取匹配结果中的第一个捕获组即可