阻止mousemove鼠標(biāo)移動或touchmove觸摸移動觸發(fā)click點(diǎn)擊事件
一、背景
最近做了自己的開源項(xiàng)目 Msw-Tools,參考了 VConsole 工具中按鈕的拖拽功能,計(jì)劃給 MSW
按鈕也增加類似的拖拽效果,并兼容PC端和手機(jī)端,但是遇到一個問題:一個按鈕綁定了多個事件,怎樣才能阻止 mousemove 或 touchmove 與 click 事件同時觸發(fā)。
MSW Tools
如上圖所示,實(shí)現(xiàn) MSW
按鈕拖拽要用到 mousedown、mousemove、mouseup 事件,對應(yīng)的移動端要用到 touchstart、touchmove、touchend 事件,但是按鈕上已經(jīng)綁定了 click 點(diǎn)擊事件,所以就要想辦法阻止 mouse 鼠標(biāo)事件或 touch 觸摸事件 與 click 事件同時觸發(fā)。不然每次拖拽按鈕后都會觸發(fā) click 事件,這顯然是不友好的。
二、問題解析
事件的執(zhí)行順序依次是:mousedown > mousemove > mouseup > click
,因此,要想 mouseup 事件執(zhí)行完后,不執(zhí)行 click 事件,可能不太好直接處理,但是可以間接的實(shí)現(xiàn)。設(shè)置一個 移動狀態(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端,還是移動端,來設(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); // 判斷是否移動了 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)移動或touchmove觸摸移動觸發(fā)click點(diǎn)擊事件的詳細(xì)內(nèi)容,更多關(guān)于阻止鼠標(biāo)移動觸發(fā)點(diǎn)擊事件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JS實(shí)現(xiàn)新聞列表無縫向上滾動實(shí)例代碼
當(dāng)新聞較多,并且空前有限的時候,使用滾動是一個不錯的選擇,本章節(jié)就通過代碼實(shí)例介紹一下如何實(shí)現(xiàn)此效果,對無縫向上滾動實(shí)例代碼感興趣的朋友一起學(xué)習(xí)吧2016-01-01webpack是如何實(shí)現(xiàn)模塊化加載的方法
這篇文章主要介紹了webpack是如何實(shí)現(xiàn)模塊化加載的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11js實(shí)現(xiàn)input的賦值小結(jié)
這篇文章主要介紹了js實(shí)現(xiàn)input的賦值問題小結(jié),在實(shí)際的開發(fā)中,為了頁面的美觀,可能用到一些框架,比如EasyUI框架,文中介紹了easyui的input框賦值代碼,感興趣的朋友一起看看吧2023-12-12apply和call方法定義及apply和call方法的區(qū)別
apply和call功能一樣,只是傳入的參數(shù)列表形式不同,本文給大家介紹apply和call方法定義及apply和call方法的區(qū)別,感興趣的朋友一起學(xué)習(xí)吧2015-11-11Jquery顏色選擇器ColorPicker實(shí)現(xiàn)代碼
這里我要分享一個自己修改的顏色選擇器,有需要的朋友參考下2012-11-11詳解JavaScript對Date對象的操作問題(生成一個倒數(shù)7天的數(shù)組)
最近項(xiàng)目需求要生成一個倒數(shù)7天的數(shù)組,下面小編把我的實(shí)現(xiàn)思路和代碼整理分享給大家,供大家參考,需要的朋友可以參考下2015-10-10javascript監(jiān)聽頁面刷新和頁面關(guān)閉事件方法詳解
本文主要介紹了javascript監(jiān)聽頁面刷新和頁面關(guān)閉事件的方法,具有一定的參考價值,下面跟著小編一起來看下吧2017-01-01