首先,請先了解一下 Events 的傳遞方式: http://www.quirksmode.org/js/events_order.html
另外,我常常拿來做範例的 Safari Handling Events 文章: http://goo.gl/r2SLD
然後,這種動作可以由 mousedown 與 mosueup/mouseleave 來取代 touchstart 與 touchend/touchcancel,大概是類似的概念,但是可能瀏覽器的反應未必會相同(這個要實際到 Mobile device 上面測試才會知道差異)。
接著是討論 click 與 mousedown 與 touchstart 之間,所有 Events 的反應。我所知道的是:
- 父元件的 mousedown, touchstart 會蓋掉子元件 click 的 capturing/bubbling。
- 自身元件的 mousedown, touchstart 一樣會蓋掉自身擁有的 click 的反應。
- touchstart 會發生,但是 touchend 或 touchcancel 不一定會發生(端看 Mobile device 而定)。
- Mobile device 的 Event 觸發型態在每種裝置上每種瀏覽器未必相同。
- Mobile device 上倘若 mousedown, touchstart, click 倘若同時綁定,有可能會重複觸發(而且還不只三次)。
最近我三不五時會收到歪國人寫信來,問我 plugins 能不能做__鍊結__或是其他關於__按鈕__的動作。我嘗試了好久,主要都是因為整個滑動元件已經綁定了 touchstart 這個動作,導致內部的子元件無法被觸發。這一點讓我覺得很困擾,主要測試了以下這些情況:
- 全部使用 Capturing 模式,不過問題是一樣的,所以跟 capturing/bubbling 無關。
- addEventListener 如果 click 跟 mousedown, touchstart 混用,則後者優先,click 可能會被忽略。
- Mobile device 上 mousedown, touchstart 都有可能會發生,而 click 也有可能發生(使用實體按鍵)。
- 因為沒有辦法穿透元件(父元件優先捕捉),所以目標元件永遠不知道你是不是觸發了他。
- 倘若子元件需要使用某個動作,父元件需要包含且永遠傳回 true 讓他 capturing 或 bubbling。
- 以上的狀況在一般電腦的瀏覽器上面也會發生。
怎麼辦?目前我想到的解法是:
子元件跟父元件一樣一律綁定 mousedown/touchstart 這兩種 Event(看你是否是觸控裝置而定)!然後,透過這兩種動作,額外來判斷他是不是 Click 還是只是單純的 mousedown/touchstart 來決定,我到底是要觸發 click 的動作,還是觸發 mousedown/touchsrart 的動作。
以 jQuery 為例子,我們可以經由 event.type 來取得傳入的動作到底是哪一個(touchstart, mousedown or click),那麼,我可以透過這個數值來決定我是否需要執行(capturing/bubbling)。
另外,在 Mobile device 上面還有一種奇妙的現象,倘若 touchstart A 被捕捉到了,然後我們另外在 plugins 以外的地方,綁定了另外一個 touchstart B 的動作,但是,那個 B 動作__不一定__會被觸發!但是,如果我在 A 動作裡面置入一個 alert(); 來中斷程式運行的話,那外部的 B 動作__就會被觸發__!關於這種情況,老實說我還想不出個所以然來。只要 A 動作被中斷,按下對話視窗的 OK 之後,B 動作就會繼續被觸發,但倘若 A 未被中斷,B 動作則不一定會動作。老實說這一點都不合常理。