label中包含input,绑定在label的事件触发两次

今天同事遇到这个很奇怪的问题,深入探查了一下,才发现其中奥妙。
最初怀疑是重复绑定造成的,但精简代码到最小,仍然出现。在排查了jQuery版本,css覆盖层,各种能想到的可能性后,仍一筹莫展。
静下心来慢慢梳理,通过输出事件来源,才猛然发现,原来绑定不同的元素,其事件来源是不同的。

找到了事件来源,似乎看到了蛛丝马迹,赶紧顺藤摸瓜。推测如下:
1.绑定在label。单击input后,触发input本身的click事件。单击label后,首先触发label本身的click事件,然后由于“某种原因”触发了input的click事件,进而事件冒泡至label,再次触发label的click事件。
2.绑定在input。单击input后,触发input本身的click事件。单击label后,由于“某种原因”触发了input的click事件。

将该示例在IE8-11、chrome中测试,表现相同。突然想起来,label是有一个for属性,标准的用法如下:

标准用法中,单击label,仍会触发input的click事件。

对以上两个示例进一步测试,替换input:radio为其他类型(如input:checkbox或input:text),表现相同。
由此可以得出结论,上述“某种原因”,是浏览器的特性。当单击与input相关(嵌套或for属性指定)的label时,自动触发input的click事件。

原来是个之前从未留意过的“坑”,如果不是今天遇到,还不知要潜伏多久。

移动端填坑

一个移动端页面,简单的展示和输入功能,时间又是压得很紧(其实每次都是这样-_-!)。原以为有了上次的经验,会很快搞定。但事与愿违,还是踩到了几个坑。

1.iscroll中input:text触发
iscroll中的input:text元素,不能直接触发。可通过在Tap事件中触发focus事件,模拟用户操作。
但在IOS中Safari下,非用户主动触发的focus事件,是不能调起输入法的。表现为需要点击两次,第一次获取焦点,第二次调起输入法。
根本原因在于Safari中keyboardDisplayRequiresUserAction属性的默认配置,没有什么好的解决方案。而网上的方案,大都是通过遍历页面,绕过iscroll对input元素浏览器默认事件的屏蔽,以允许用户触发focus事件。
其他还有“光标移位”、“文本框被遮盖”等,是由于transform造成,就不一一列举了。切记iscroll并不适用于所有情况,要选择合适的场景使用。

2.浏览器对input:datetime和input:datetime-local支持不足
需求中要输入日期和时间,且对于展示格式有要求。原本计划使用HTML5中的标准标签,可惜浏览器太支持太差。对于input:date的支持倒是相对较好,可以不满足输入时间的要求。并且,这些元素都不能满足对于展示格式的要求。
无奈只能使用第三方方案。找来找去发现了一家mobiscroll,效果可以用惊艳来形容。但问题是,他是收费的,只有15天的试用期。好在这家公司良心大大的,提供了一个单一功能的开源版本,用着还不错。

3.浏览器对input:file调用媒体设备的支持不一致
需求中要求直接调用摄像头拍照或选择文件上传照片。好在目前这个支持都还可以,只是有些属性不同的设备解析不同。multiple属性会造成IOS下无法调用摄像头,capture=”camera”属性会造成MIUI7下无法选择文件。最兼容的使用方式是,只设置accept=”image/*”属性。
文件上传的方式,可参考mozilla开发者中心。使用File对象访问文件信息,使用window.URL.createObjectURL方法预览图片,使用FormData对象配合XMLHttpRequest对象实现文件的异步上传。好在这些特性移动端支持的还不错,统一标准万岁!

参考链接:
Mobile Safari Autofocus text field
keyboardDisplayRequiresUserAction
HTML Media Capture
如何在web应用程序中使用文件
H5拍照应用开发经历的那些坑儿