阻止mousemove鼠標(biāo)移動(dòng)或touchmove觸摸移動(dòng)觸發(fā)click點(diǎn)擊事件
一、背景
最近做了自己的開源項(xiàng)目 Msw-Tools,參考了 VConsole 工具中按鈕的拖拽功能,計(jì)劃給 MSW 按鈕也增加類似的拖拽效果,并兼容PC端和手機(jī)端,但是遇到一個(gè)問題:一個(gè)按鈕綁定了多個(gè)事件,怎樣才能阻止 mousemove 或 touchmove 與 click 事件同時(shí)觸發(fā)。

MSW Tools
如上圖所示,實(shí)現(xiàn) MSW 按鈕拖拽要用到 mousedown、mousemove、mouseup 事件,對應(yīng)的移動(dòng)端要用到 touchstart、touchmove、touchend 事件,但是按鈕上已經(jīng)綁定了 click 點(diǎn)擊事件,所以就要想辦法阻止 mouse 鼠標(biāo)事件或 touch 觸摸事件 與 click 事件同時(shí)觸發(fā)。不然每次拖拽按鈕后都會觸發(fā) click 事件,這顯然是不友好的。
二、問題解析
事件的執(zhí)行順序依次是:mousedown > mousemove > mouseup > click,因此,要想 mouseup 事件執(zhí)行完后,不執(zhí)行 click 事件,可能不太好直接處理,但是可以間接的實(shí)現(xiàn)。設(shè)置一個(gè) 移動(dòng)狀態(tài)的開關(guān),并加上 延遲處理 就可以達(dá)到"阻止 click 事件"的目的。
三、代碼實(shí)現(xiàn)
因?yàn)?Msw-Tools 工具是使用 Svelte 框架開發(fā)的,所以這里展示 Svelte 部分代碼。
<!-- msw.svelte -->
<div class="msw-container">
<div on:click|stopPropagation={showModal}
bind:this={btnDOM}
class="msw-show">MSW</div>
</div>
<script>
import { onMount } from "svelte";
// 區(qū)分當(dāng)前是PC端,還是移動(dòng)端,來設(shè)置 mouse 事件 或 touch 事件
function getModels() {
let userAgentInfo = navigator.userAgent;
let mobileAgents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
return mobileAgents.reduce((prev, ua)=>{
return userAgentInfo.includes(ua) || prev
}, false)
};
const MSW_BTN_POSITION = '__MSW_BTN_POSITION__'
let show = false;
let btnDOM = null;
let isDrop = false;
let isMoving = false;
let offset = {
x: 0,
y: 0,
};
let offsetDown = {};
let dropTimer = null;
let isMobile = getModels();
let btnW = 0;
let btnH = 0;
let clientW = 0;
let clientH = 0;
let eventType = isMobile ? 'touchstart' : 'mousedown';
// DOM 掛載后執(zhí)行
onMount(async () => {
// 初始化,獲取按鈕、視口寬高、計(jì)算邊界值
initClientData();
return () => {
// component 卸載后,解除事件綁定
btnDOM.removeEventListener(eventType, btnMousedown)
}
});
function initClientData() {
// 按鈕位置保存在本地,可以記住位置,避免每次去拖拽
let local = localStorage.getItem(MSW_BTN_POSITION)
if (local) {
offset = JSON.parse(local)
btnMove()
}
let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
clientW = isMobile ? w : document.body.clientWidth
clientH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
btnW = btnDOM.offsetWidth
btnH = btnDOM.offsetHeight
// 給按鈕綁定 mousedown 或 touchstart 事件
btnDOM.addEventListener(eventType, btnMousedown)
}
function eventHandle (type) {
if (isMobile) {
document[`${type}EventListener`]('touchmove', mousemove);
document[`${type}EventListener`]('touchend', mouseup);
} else {
document[`${type}EventListener`]('mousemove', mousemove);
document[`${type}EventListener`]('mouseup', mouseup);
}
}
function showModal () {
if (!isMoving) {
show = true;
}
}
function btnMousedown(e) {
e = e || window.event
isDrop = true
offsetDown = {
...getOffset(e)
};
eventHandle('add')
}
function mousemove(e) {
e = e || window.event
if (isDrop) {
let data = getOffset(e);
// 判斷是否移動(dòng)了
isMoving = !(offsetDown.x === data.x && offsetDown.y === data.y)
let x = data.x - btnW / 2;
let y = data.y - btnH / 2;
if (x > 5 && x < (clientW-btnW - 5)) {
offset.x = x;
}
if (y > 5 && y < (clientH-btnH - 5)) {
offset.y = y;
}
if (isMoving) {
btnMove()
}
clearTimeout(dropTimer);
dropTimer = setTimeout(()=>{
isMoving = false;
clearTimeout(dropTimer);
dropTimer = null;
}, 300);
}
}
function mouseup() {
if (isDrop) {
window.localStorage.setItem(MSW_BTN_POSITION, JSON.stringify(offset))
eventHandle('remove')
}
isDrop = false
// console.log('mouseup')
}
function btnMove (){
btnDOM.style.cssText = `
left: ${offset.x}px;
top: ${offset.y}px;
right: auto;
bottom: auto;
`
}
function getOffset(e) {
return isMobile ? {
x: e.targetTouches[0].clientX,
y: e.targetTouches[0].clientY,
} : {
x: e.clientX,
y: e.clientY,
}
}
</script>
<style lang="scss" type="text/scss">
@import "index";
</style>- 效果體驗(yàn):msw-tools
以上就是阻止mousemove鼠標(biāo)移動(dòng)或touchmove觸摸移動(dòng)觸發(fā)click點(diǎn)擊事件的詳細(xì)內(nèi)容,更多關(guān)于阻止鼠標(biāo)移動(dòng)觸發(fā)點(diǎn)擊事件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript獲取URL參數(shù)的幾種方法小結(jié)
在Web開發(fā)中,經(jīng)常需要從URL中提取參數(shù)來進(jìn)行相應(yīng)的操作,本文將深度解析在JavaScript中獲取URL參數(shù)的幾種方法,并附帶一些擴(kuò)展與高級技巧,希望對你有所幫助2024-09-09
javascript實(shí)現(xiàn)網(wǎng)頁背景煙花效果的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)網(wǎng)頁背景煙花效果的方法,涉及javascript數(shù)學(xué)運(yùn)算及頁面元素動(dòng)態(tài)操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08
如何利用JavaScript實(shí)現(xiàn)排序算法淺析
排序算法是筆試中經(jīng)常出現(xiàn)的,提起排序算法就一定要提下算法復(fù)雜度和大O表示法,算法復(fù)雜度是指算法在編寫成可執(zhí)行程序后,運(yùn)行時(shí)所需要的資源,資源包括時(shí)間資源和內(nèi)存資源,這篇文章主要給大家介紹了關(guān)于如何利用JavaScript實(shí)現(xiàn)排序算法的相關(guān)資料,需要的朋友可以參考下2021-11-11
前端項(xiàng)目中.env文件的原理和實(shí)現(xiàn)方法代碼
這篇文章主要介紹了前端項(xiàng)目中.env文件原理和實(shí)現(xiàn)方法的相關(guān)資料 ,.env文件是一種常見的方法,用來存儲項(xiàng)目的環(huán)境變量和敏感信息,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-03-03
Javascript中引用類型傳遞的知識點(diǎn)小結(jié)
這篇文章主要給大家介紹了關(guān)于Javascript中引用類型傳遞的知識點(diǎn),文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03
uniapp自定義頁面跳轉(zhuǎn)loading的實(shí)現(xiàn)代碼
有些頁面加載起來比較慢,為了加強(qiáng)用戶體驗(yàn)效果,所以一般都會做一個(gè)頁面加載等待的提示,頁面加載完成后消失,下面這篇文章主要給大家介紹了關(guān)于uniapp自定義頁面跳轉(zhuǎn)loading的實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-06-06
E3 tree 1.6在Firefox下顯示問題的修復(fù)方法
tree 在Firefox下只顯示一句話,用firebug查看頁面元素觀察發(fā)現(xiàn),兩個(gè)script導(dǎo)入被一個(gè)<script>分隔開了,顯然是document.write的問題.由于Firefox對js規(guī)范的檢查比較嚴(yán)格,肯定一些字符輸出的的時(shí)候沒有轉(zhuǎn)義2013-01-01
JS實(shí)現(xiàn)的碰撞檢測與周期移動(dòng)完整示例
這篇文章主要介紹了JS實(shí)現(xiàn)的碰撞檢測與周期移動(dòng),結(jié)合完整實(shí)例形式分析了javascript結(jié)合時(shí)間函數(shù)的頁面元素屬性動(dòng)態(tài)操作及事件響應(yīng)相關(guān)使用技巧,需要的朋友可以參考下2019-09-09

