阻止mousemove鼠标移动或touchmove触摸移动触发click点击事件

 更新时间:2023年06月13日 11:50:16   作者:天問  
这篇文章主要为大家介绍了阻止mousemove或touchmove与click事件同时触发技巧,一个按钮绑定了多个事件,所以就要想办法阻止 mouse 鼠标事件或 touch 触摸事件 与 click 事件同时触发,不然每次拖拽按钮后都会触发 click 事件,这显然是不友好的

一、背景

最近做了自己的开源项目 Msw-Tools,参考了 VConsole 工具中按钮的拖拽功能,计划给 MSW 按钮也增加类似的拖拽效果,并兼容PC端和手机端,但是遇到一个问题:一个按钮绑定了多个事件,怎样才能阻止 mousemove 或 touchmove 与 click 事件同时触发

MSW Tools

如上图所示,实现 MSW 按钮拖拽要用到 mousedown、mousemove、mouseup 事件,对应的移动端要用到 touchstart、touchmove、touchend 事件,但是按钮上已经绑定了 click 点击事件,所以就要想办法阻止 mouse 鼠标事件或 touch 触摸事件 与 click 事件同时触发。不然每次拖拽按钮后都会触发 click 事件,这显然是不友好的。

二、问题解析

事件的执行顺序依次是:mousedown > mousemove > mouseup > click,因此,要想 mouseup 事件执行完后,不执行 click 事件,可能不太好直接处理,但是可以间接的实现。设置一个 移动状态的开关,并加上 延迟处理 就可以达到"阻止 click 事件"的目的。

三、代码实现

因为 Msw-Tools 工具是使用 Svelte 框架开发的,所以这里展示 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";
  // 区分当前是PC端,还是移动端,来设置 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 挂载后执行
  onMount(async () => {
    // 初始化,获取按钮、视口宽高、计算边界值
    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>

以上就是阻止mousemove鼠标移动或touchmove触摸移动触发click点击事件的详细内容,更多关于阻止鼠标移动触发点击事件的资料请关注脚本之家其它相关文章!

相关文章

  • canvas绘制表盘时钟

    canvas绘制表盘时钟

    本文主要分享了canvas绘制表盘时钟的示例代码。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • 基于JS实现新闻列表无缝向上滚动实例代码

    基于JS实现新闻列表无缝向上滚动实例代码

    当新闻较多,并且空前有限的时候,使用滚动是一个不错的选择,本章节就通过代码实例介绍一下如何实现此效果,对无缝向上滚动实例代码感兴趣的朋友一起学习吧
    2016-01-01
  • webpack是如何实现模块化加载的方法

    webpack是如何实现模块化加载的方法

    这篇文章主要介绍了webpack是如何实现模块化加载的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • 微信小程序实现星级评分与展示

    微信小程序实现星级评分与展示

    这篇文章主要为大家详细介绍了微信小程序实现星级评分与展示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • js实现input的赋值小结

    js实现input的赋值小结

    这篇文章主要介绍了js实现input的赋值问题小结,在实际的开发中,为了页面的美观,可能用到一些框架,比如EasyUI框架,文中介绍了easyui的input框赋值代码,感兴趣的朋友一起看看吧
    2023-12-12
  • javascript继承机制实例详解

    javascript继承机制实例详解

    这篇文章主要介绍了javascript继承机制,以实例形式详细分析了javascript继承的原理与基于原型链的继承实现方法,具有不错的参考借鉴价值,需要的朋友可以参考下
    2014-11-11
  • apply和call方法定义及apply和call方法的区别

    apply和call方法定义及apply和call方法的区别

    apply和call功能一样,只是传入的参数列表形式不同,本文给大家介绍apply和call方法定义及apply和call方法的区别,感兴趣的朋友一起学习吧
    2015-11-11
  • Jquery颜色选择器ColorPicker实现代码

    Jquery颜色选择器ColorPicker实现代码

    这里我要分享一个自己修改的颜色选择器,有需要的朋友参考下
    2012-11-11
  • 详解JavaScript对Date对象的操作问题(生成一个倒数7天的数组)

    详解JavaScript对Date对象的操作问题(生成一个倒数7天的数组)

    最近项目需求要生成一个倒数7天的数组,下面小编把我的实现思路和代码整理分享给大家,供大家参考,需要的朋友可以参考下
    2015-10-10
  • javascript监听页面刷新和页面关闭事件方法详解

    javascript监听页面刷新和页面关闭事件方法详解

    本文主要介绍了javascript监听页面刷新和页面关闭事件的方法,具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01

最新评论