问题描述:在手机上,发现网页上所有的表单元素轻触都不能聚焦
1、第一次探索和尝试
为测试元素加上click事件和focus事件,轻触的时候发现click触发了,但是focus没有触发,有点奇怪啊,第一次的尝试解决方案:就在click的事件回调函数中调用focus方法;虽然最后聚焦成功了,但是仅仅只是处理了一个表单元素,页面还有n个元素需要这么处理,头疼;所以打算找原因,从底层根本处理问题。
2、定位原因
在google和Baidu上一顿搜索,发现已有类似的问题,是因为fastclick;问题来了,fastclick是啥?
大家应该都知道移动端里有双击缩放的功能,那浏览器是怎么区分是双击还是单击呢,为了解决这个问题,浏览器是先触发touch事件,经过touchstart -> touchmove -> touchend ,300ms之后才会触发click事件;那又有一个问题了,假如网页不需要双击缩放的效果,那么300ms就显得很多余了,还搞得网页有点卡卡的感觉,没有丝滑的感觉很不爽啊,所有就有了fastclick。更详细文章请看:300ms的由来以及解决办法
总得说fastclick就是解决300ms的问题,阻止原生的click事件,并立即使用sendClick发送click事件。
fastclick是啥原因导致了不能聚焦,之前怎么没有暴露出来呢?
具体定位流程就不说了,直接贴代码:
if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
this.targetElement = null;
return false;
}
this.focus(targetElement);
this.sendClick(targetElement, event);
if (!deviceIsIOS || targetTagName !== 'select') {
this.targetElement = null;
event.preventDefault();
}
return false;
这段代码是fastclick 的touchend中的一段,代表需要触发点击事件,并且需要聚焦的,这里都没啥问题,是聚焦的focus方法有问题,如下:
FastClick.prototype.focus = function(targetElement) {
var length;
if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' && targetElement.type !== 'email') {
length = targetElement.value.length;
targetElement.setSelectionRange(length, length);
} else {
targetElement.focus();
}
};
普通的input元素是使用setSelectionRange聚焦的,这个方法在高版本的ios上不知为啥就不能使用了,导致不能聚焦。
3、解决方法
- 1 使用focus替换setSelectionRange方法,但是这个有操作成本,需要改fastclick源码
- 2 直接把fastclick去掉,因为现在很多浏览器已经没有300ms的延迟了,再配合css解决
html {
touch-action: manipulation;
}
touch-action属性详解
manipulation
浏览器只允许进行滚动和持续缩放操作。任何其它被auto值支持的行为不被支持。启用平移和缩小缩放手势,但禁用其他非标准手势,例如双击以进行缩放。 禁用双击可缩放功能可减少浏览器在用户点击屏幕时延迟生成点击事件的需要。 这是“pan-x pan-y pinch-zoom”(为了兼容性本身仍然有效)的别名。