pocket-manual icon indicating copy to clipboard operation
pocket-manual copied to clipboard

浏览器兼容性问题汇总

Open FishPlusOrange opened this issue 6 years ago • 0 comments

之前浏览器兼容性问题都是分开记录的,Issues 现在支持删除,所幸就把单独记录的都删了,汇总到这里。

这些问题大部分都是以前开发过程中遇到的,现在的项目基本上不要求兼容低版本 IE,所以汇总的问题数可能不是很多,就当做是一个简单的记录吧。

IE11 浏览器下 get 请求缓存问题

开发过程中遇到一个问题:

IE11 浏览器下,发起同一个 GET 请求(参数一致),无法获取到实时数据。

经排查发现:

默认情况下,当 IE11 浏览器发起的 GET 请求参数一致时,只有第一次请求会发送到服务器并返回结果(状态码200)。对于后续发起的相同请求,浏览器直接使用缓存数据(状态码304),从而无法获取到实时数据,导致业务出现问题。

解决方案:

  • 添加随机数

在相应的 GET 请求后面添加一个随机数参数,比如时间戳:

// url 为原请求路径
let newUrl = `${url}&t=${new Date().getTime()}`;
  • 修改 jQuery 的 AJAX 配置

通过设置 cachefalse 以禁止缓存:

$.ajax({
    // ...
    cache: false
    // ...
})

// 或

$.ajaxSetup({ cache: false })
  • 使用 POST 请求

POST 请求的响应默认是不可以缓存的(除非响应头设置了 Expires 或 Cache-Control 控制缓存),所以使用 POST 请求也可以解决该问题,只是这样不符合 HTTP 规范和语义化。

IE11 浏览器下 babel 编译后的部分 ES6 语法仍然报 undefined 错误

最近参与一个项目,该项目并不是真正意义上的前后端分离,要求兼容 IE11,前端构建使用 gulp,开发使用了 ES6 标准。本地开发都是使用 chrome ,基本上没有问题,但是在 IE11 浏览器上报错,比如 'Symbol' is undefined'Promise' is undefined

原因其实很简单,项目前端构建这一步 babel 没有对相关 ES6 新 API 进行编译。因为 babel 默认只转换新语法,而不转换新 API,比如 SymbolPromiseGenerator 等。如果要使用这些新 API,必须使用 babel-polyfill 为当前环境提供垫片。

由于该项目都是采用文件引入的方式,没有模块化,直接用 import 方式报错,相关解决方案:

  1. npm install babel-polyfill --save

  2. node_modules/babel-polyfill/dist 下找到 polyfill.min.js,将其引入到项目公共头部:

<script src="src/polyfill.min.js"></script>

如果项目是基于模块化开发,在入口文件 import 即可:

import 'babel-polyfill'

IE8 浏览器下 new Date('YYYY-MM-DD') 返回 NaN

开发过程中,发现在 IE8 浏览器下通过 new Date('YYYY-MM-DD') 创建一个指定日期的 Date 对象,返回的却是 NaN:

// IE8 浏览器下
var date = new Date('1994-04-05'); // NaN

在网上查找到了一个解决方案,即在 new Date() 前先调用 parseISO8601 方法:

var date = new Date(parseISO8601('1994-04-05'));

function parseISO8601(dateStringInRange) {
    var isoExp = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/,
        date = new Date(NaN), month,
        parts = isoExp.exec(dateStringInRange);
    if(parts) {
        month = +parts[2];
        date.setFullYear(parts[1], month - 1, parts[3]);
        if(month != date.getMonth() + 1) {
            date.setTime(NaN);
        }
    }
    return date;
} 

IE 浏览器下 td 边框消失

导致 td 边框消失的原因是该标签同时存在 position: relative;background-color 属性。

推荐的解决方案是在该 td 下添加 div 并设置 position: relative; 把所有内容放在 div 中。

IE 浏览器下由于请求路径过长导致发送 GET 请求时报500错误

开发过程中通过 GET 请求下载或导出文件:

  1. 通过 window.open 打开新窗口跳转请求:
// url 为请求路径
window.open(url + '?params=' + encodeURI(params));
  1. 通过 window.location.href 在本页面跳转请求:
// url 为请求路径
window.location.href = url + '?params=' + encodeURI(params);
  1. 通过模拟 form 表单提交打开新窗口跳转请求:
// url 为请求路径
var form = document.createElement('form');
form.target = '_blank';
form.action = url;
form.method = 'get';
form.style.display = 'none';

var opt = document.createElement('textarea');
opt.name = 'params';
opt.value = params;
form.appendChild(opt);

document.body.appendChild(form);
form.submit();
fotm.remove();

方法1和3可配置 target 属性(方法1的 target 属性默认为 _blank,方法3的 target 属性默认为 _self),方法2仅能在本页面跳转(等同于 a 标签且 target 属性为 _self)。开发过程中发现部分版本 IE 浏览器下,打开新窗口跳转请求下载完成后,新窗口无法自动关闭,可通过配置 target 属性为 _self 解决该问题。

方法1和2使用 encodeURI 转码是因为 IE 浏览器下请求路径带中文参数发送 GET 请求报400错误。方法3不需要使用 encodeURI 转码是因为通过模拟 form 表单提交打开新窗口跳转请求会自动对中文参数进行转码。

测试过程中发现部分情况下 IE 浏览器会报500错误。

经研究,IE 浏览器对最大请求路径长度进行了限制,限制长度为2048字节,这个限制对 POST 请求和 GET 请求的 URL 均适用。因为 IE 浏览器下需要对请求路径中的中文参数进行转码,其可能导致请求路径长度超出限制,当发送 GET 请求时 IE 浏览器会报500错误。

解决方案是使用 POST 请求:

// url 为请求路径
var form = document.createElement('form');
form.target = '_blank';
form.action = url;
form.method = 'post'; // 把 GET 请求改成 POST 请求
form.style.display = 'none';

var opt = document.createElement('textarea');
opt.name = 'params';
opt.value = params;
form.appendChild(opt);

document.body.appendChild(form);
form.submit();
fotm.remove();

IE 浏览器下由于请求路径带中文参数导致发送 GET 请求时报400错误

可通过 encodeURI 函数对中文参数进行编码:

// url 为请求路径
window.location.href = url + '?params=' + encodeURI(params);

IE9 浏览器下在拖拽、剪切、删除操作时无法触发 propertychange 事件

可在获得输入框焦点时设置定时器周期性触发 propertychange 事件以兼容该问题:

$('input').each(function() {
    var $this = $(this);
    var _interval;
    $this.focus(function() {
        _interval = setInterval(function() {
            $this.trigger('propertychange');
        }, 300);
    });
    $this.blur(function() {
        clearInterval(_interval);
    });
});

低版本 IE 浏览器下无法触发 oninput 事件

oninput 用于实时监听输入框 value 变化,不同于 onchange 事件要在值改变且失去焦点时触发。

oninput 是 HTML5 标准事件,低版本 IE 浏览器(IE9 以下)不支持,可使用 IE 浏览器专有事件 onpropertychange 兼容

在 jQuery 中 oninputonpropertychange 分别对应事件 inputpropertychange

二者区别:

  • oninput 在 value 改变时实时触发(通过 js 改变 value 不触发),onpropertychange 在任何属性改变时均会触发。

  • 在 JS 事件动态绑定方式上,oninput 可通过普通事件绑定方式和 addEventListener 注册。onpropertychange 只能通过普通事件绑定方式,所以在 jQuery 中其不能通过事件委托的方式绑定事件。

IE 浏览器下 iframe 弹窗中输入框光标丢失(无法输入)问题

在开发过程中遇到这样一个问题,IE 浏览器下弹出一个 iframe 弹窗,第一次可以正常获得输入框焦点,关闭弹窗后再打开(未刷新页面),无法获得输入框焦点,即无法输入。

网上查到一种方法,通过 IE 特有的方法 CollectGarbage() 来回收内存,经尝试问题依然没有得到解决。

个人理解造成该问题的主要原因是,IE 浏览器下在关闭(移除)弹窗(iframe 外层容器)时,iframe 并没有从 DOM 中移除,导致再打开弹窗时 DOM 冲突。经研究,主要有两种解决方案:

  1. 在移除弹窗时,先移除 iframe:
// window.parent.document 表示跨 iframe 操作父页面元素
$('iframe', window.parent.document).remove();
  1. 每次打开弹窗时,手动获得输入框焦点:
$('input').focus();

本人解决该问题时采用方案二,因为在实际解决过程中发现方案一在 IE10 版本下(非仿真模式)不可行,所以推荐方案二

低版本 IE 浏览器下绝对定位的元素未设置背景时无法响应鼠标点击或悬浮事件

推荐的解决方案是通过设置 background 属性 hack:

div {
    background: url(about:blank);
}

其他解决方案:

  • 不使用绝对定位

  • 添加背景色

  • 添加透明背景图片

FishPlusOrange avatar Jan 23 '19 12:01 FishPlusOrange