记录fastclick中一次手动触发click事件失败

在昨天的一个移动端项目中引入fastclick后手动触发click事件失败,查看了文档也没有找到解决的办法,最后经过看fastclick源码才解决。
若是不想看中间这么多文字,能够直接翻到最后看结论。javascript

还原事故现场

想要实现的功能为点击div1的时候手动触发input的click事件。代码以下:java

<style>
    <div>
        <div class="div1" @click="handleClick">
            input标签是隐藏的,只能看到div1
        </div>
        <input type="file" style="display: none" res="input">
    </div>
</style>

<script>
    export default {
        methos: {
            handleClick() {
                this.$refs.input.click()
            }
        }
    }
</script>

在没有引入fastclick的时候,能够按照预期工做,引入以后,在Android中也能够正常工做,可是在iOS却不管如何也不行。即便在input标签加上needsclick类也不行。
神奇的是若是连续手动触发两次click事件,则在iOS中就能够正常工做了!!git

代码以下:github

handleClick() {
    this.$refs.input.click()
    this.$refs.input.click()
}

想来想去,缘由只能出在fastclick身上,首先看了文档,并无发现解决的方法,只能去看源码了。虽然第一次用fastclick的时候就读过代码,当时只不过为了知道大概实现原理泛泛的读了一遍,不够细致。此次又从新看了一遍。关于源码的解读网上有不少,这里就不细说,代码不长,建议最好本身读一读。chrome

追踪溯源,找到问题缘由症结

看完源码,就能够回答以前的疑问了。less

一、为何安卓能够正常工做?

代码函数

if (deviceIsAndroid) {
    metaViewport = document.querySelector('meta[name=viewport]');

    if (metaViewport) {
        // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
        if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
            return true;
        }
        // Chrome 32 and above with width=device-width or less don't need FastClick
        if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
            return true;
        }
    }

// Chrome desktop doesn't need FastClick (issue #15)
} else {
    return true;
}

在fastclick刚运行的时候,就判断是否须要使用fastclick,个人安卓测试机chrome大于32 且设置了width=device-width。因此在安卓下我点击使用的原生click事件固然没问题。测试

二、为何iOS须要手动触发两次click事件才能够?

这就是此次“事故”的关键所在,当我点击的时候,一共触发了单词click事件,其中第一次为点击div触发,后两次为手动触发input的click事件。this

第一次click事件时,fastclick在onTouchStart中将targetElement设置为div1,
此次成功执行sendClick() ,目标并非咱们想要的input。scala

紧接着是第一次手动触发click事件,可是由于是经过element.click()函数手动触发,因此没有onTouchStart这个过程,所以此时targetElement固然仍是div1 !!! 这时needsClick返回了false,从而致使onClick中onMouse函数也返回了false,并终止了事件,随后就将targetElement置为null。

在第二次手动click事件中,由于此时targetElement为null,因此在onMouse中返回true,接着从而顺利触发了原生click事件。

if (!this.targetElement) {
    return true;
}
三、为何在input标签加上needsclick也不能成功触发click事件?

由于第一次手动执行click() 的时,这时候的targetElement仍是div1,即点击时的元素,而我将needsclick绑定在input上了,所以固然在targetElement上找不到needsclick了。
此时咱们也就找到了解决问题的办法:将needsclick绑定在div1,即实际点击的元素上。

结论及收获

  • 若是想触发原生click事件,请将needsclick绑定在实际点击的元素上,即e.targe上,而不是你手动触发的元素上。这能够说是fastclick的一个小bug,由于以前的点击影响了后面的点击。

  • 只能在click的回调函数中手动触发element.click() ,不然无效,有兴趣的能够试试。这个在MDN上没写,算是意外收获。

相关文章
相关标签/搜索