背景
上午樓主遇到一個需要
處理輕按兩下事件
的需求,在這裡介紹下
如何在觸發doubleCLick時間的時候, 不觸發click事件
的解決辦法, 順便分享給大家。
問題闡述
首先, 我們的DOM 是天然支援dbClick 事件的, 線上demo:
https://codepen.io/scaukk/pen/BaBoYeO
可以清晰的看到, 輕按兩下之後, 觸發處理輕按兩下事件的邏輯, 但是同時也觸發了兩次click事件:

這個副作用不是我們預期的, 需要處理一下。
解決辦法
解決辦法也很簡單:
延遲 click事件的處理, 直到判斷這個click 不在 doubleClick 中。
原理
這個延遲的click事件會放在一個
Promise 隊列
中, 并處于
pending
狀态。
當doubleClick事件觸發之後, 就取消所有的Pending Promises, 這些事件也就不會執行。
可取消的Promise
要處理這些處于 penging 狀态的Promise, 我們需要用到可取消的Promise, 這個話題我在另一篇文章中讨論過, 有興趣的可以看一下:
https://segmentfault.com/a/1190000019456742
下面是一個可以cancel的Promise的簡單實作:
export const cancellablePromise = promise => {
let isCanceled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
value => (isCanceled ? reject({ isCanceled, value }) : resolve(value)),
error => reject({ isCanceled, error }),
);
});
return {
promise: wrappedPromise,
cancel: () => (isCanceled = true),
};
};
複制
要解決開頭提到的這個問題, 我們就需要用到這個大殺器。
先看下最終的結果,輕按兩下一下:
主要代碼:
const EnhancedClickableBox = stopTriggerClicksOnDoubleClick(ClickableBox)
const DoubleClickExample = () => (
<EnhancedClickableBox
onClick={() => console.log("on click")}
onDoubleClick={() => console.log("on double click")}
/>
);
const App = () => {
return (
<DoubleClickExample />
)
}
ReactDOM.render(<App />, document.getElementById("app"));
複制
線上Demo:
https://codepen.io/scaukk/pen/yLBYojv
Hooks 版本
const ClickableBox = ({ onClick, onDoubleClick }) => {
const [handleClick, handleDoubleClick] = useClickPreventionOnDoubleClick(onClick, onDoubleClick);
return (
<button onClick={handleClick} onDoubleClick={handleDoubleClick}>
Click or double click
</button>
);
};
const DoubleClickExample = () => (
<ClickableBox
onClick={() => console.log("on click")}
onDoubleClick={() => console.log("on double click")}/>
);
const App = () => {
return (
<DoubleClickExample />
)
}
ReactDOM.render(<App />, document.getElementById("app"));
複制
https://codepen.io/scaukk/pen/OJLyrOM
是不是很簡單~
結語
處理輕按兩下事件的時候, 最好還是處理掉不必要的click調用, 免得産生bug.
文中若有錯誤,歡迎指出, 歡迎留言交流。