第一次碰到自带的歧视的bug,IE 11泥潭不解释。
起因
ant-design-vue的RangePicker在IE11下calendar panel无法正常展开,看图。
具体的相关讨论看参考链接中的
ant-design-vue部分。
因为我知道IE和firefox、chrome下时间处理有问题(es5之前),以为是Date的问题,所以我的调试方向就走偏了,顺便介绍下Date.parse的行为,new Date('字符串'),内部使用Date.parse解析。
Date.parse行为诡异
参考链接部分有大量的Date知识总结,多多浏览。
Date.parse在ES5之前不同浏览器,行为差异很大。现在我只能重现一下IE下的,Chrome和firefox版本都太高,已经修正这个问题。如果想看以前的兼容性问题,看这篇博客javascript-and-dates-what-mess
// 控制台
new Date('2019-07-02')
// Tue Jul 02 2019 08:00:00 GMT+0800 (中国标准时间)
new Date('2019/07/02')
// Tue Jul 02 2019 00:00:00 GMT+0800 (中国标准时间)
看到区别了吗?time部分,一个从0点开始,一个从8点开始,为啥呢?看看MDN怎么说吧。
MDN文档不推荐在ES5之前使用Date.parse方法,因为字符串的解析完全取决于实现。直到至今,不同宿主在如何解析日期字符串上仍存在许多差异,因此最好还是手动解析日期字符串(在需要适应不同格式时库能起到很大帮助)。
注意:如果你要兼容IE,对日期处理,请使用专门的类库,例如:moment.js, day.js之类。
Date#toString()
顺便提一下,Date#toString()竟然有规范,看这里Date.toString,所以从Date字符串中解析提取一些字符可以放心大胆的用。以后推荐使用Intl对象是 ECMAScript 国际化 API 的一个命名空间,它提供了精确的字符串对比、数字格式化,和日期时间格式化
/**
* 提取GMT时区
* @param date
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString#Description
* @returns ''或者GMT,或者GMT+0000或者GMT-0000;其中0000代表GMT偏移量,是四位前两位表示hours小时,后两位表示minuts分钟.
*/
function extractTimezoneOffsetWithGMT(date) {
if (!date) {
return '';
}
const dateTimeStr = date.toString(); // Thu May 23 2019 14:52:15 GMT+0800 (中国标准时间)
const gmtIndexStart = dateTimeStr.indexOf('GMT');
const timezoneEnd = dateTimeStr.indexOf(' ', gmtIndexStart);
return dateTimeStr.substring(gmtIndexStart, timezoneEnd);
}
placeholder和input事件
和
ant-design-vue维护者沟通之后,得知这个bug在ant-design-vue的英文语言模式下不会有问题,维护的小伙伴,推测语言环境不同,有可能导致编译的代码不同(也有道理,现在js都上编译器,你不知道编译后代码有多大变化,当时已经提到了placeholder,我没注意)。
思路:英文版和中文版,最大的不同应该是语言文件,涉及到RangePicker只有时间格式和placeholder,时间格式已经怀疑过,因为底层使用moment库处理,所以没问题。所以只能看看placeholder兼容性。
placeholder兼容性
注意:看下Known issues的tab页签,看到第二条,我震惊了,为啥当placeholder为中文时会触发input事件???
input事件的兼容性
重现IE11当placeholder="中文"时,触发input事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>placeholder</title>
</head>
<body>
<div id="content">
<input type="text" placeholder="english" id="en">
<input type="text" placeholder="中文" id="cn">
</div>
<script>
window.onload = function () {
var enInput = document.getElementById('en');
var cnInput = document.getElementById('cn');
enInput.addEventListener('input', function (evt) {
console.log('en inpu');
});
cnInput.addEventListener('input', function (evt) {
console.log('cn input');
});
}
</script>
</body>
</html>
临时处理方案
知道了原因就很容易处理了,只要input的placeholder=""就搞定了,虽然不好看,总比有bug好。
<!-- 重置placeholder,因为默认有语言文件,placeholder默认有文字的 -->
<a-range-picker @change="onChange" :placeholder="['', '']"/>
到这里才找到真正造成
RangePicker问题的原因,反馈给了ant-desing-vue维护小伙伴,他们下次修复上线。
总结
解决问题的思路很重要,很重要,以后如果碰到IE下的问题,第一时间https://caniuse.com/网站看兼容性,被IE坑怕了,兼容IE,就是在浪费生命。
参考
javascript-and-dates-what-mess