阅读 157

前端小纠结--自带“歧视性”的IE11 input事件

第一次碰到自带的歧视的bug,IE 11泥潭不解释。

起因

ant-design-vueRangePicker在IE11下calendar panel无法正常展开,看图。

RangePicker

具体的相关讨论看参考链接中的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兼容性

caniuse-placeholder

注意:看下Known issues的tab页签,看到第二条,我震惊了,为啥当placeholder为中文时会触发input事件???

input事件的兼容性

caniuse-input-event

重现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>

复制代码

placeholder-fire-input-event

临时处理方案

知道了原因就很容易处理了,只要input的placeholder=""就搞定了,虽然不好看,总比有bug好。

<!-- 重置placeholder,因为默认有语言文件,placeholder默认有文字的 -->
 <a-range-picker @change="onChange" :placeholder="['', '']"/>
复制代码

到这里才找到真正造成RangePicker问题的原因,反馈给了ant-desing-vue维护小伙伴,他们下次修复上线。

总结

解决问题的思路很重要,很重要,以后如果碰到IE下的问题,第一时间https://caniuse.com/网站看兼容性,被IE坑怕了,兼容IE,就是在浪费生命。

参考

Date.parse

阮一峰 JavaScript标准参考教程 Date对象

javascript-and-dates-what-mess

JS原生Date类型方法的一些冷知识

wxyyxc1992--时间与日期

IE11日历选择框有值的情况无法打开选择框

ie11下组件DatePicker 日期选择框不显示且控制台报错

IE下点击RangePicker会闪一下关闭,openChange执行3次

欢迎加入群聊

如果入群失败,添加个人微信,拉你入群,验证消息:前端交流

关注公众号,发现更多精彩内容。

关注下面的标签,发现更多相似文章
评论