記錄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上沒寫,算是意外收穫。

相關文章
相關標籤/搜索