首页 > 其他分享 >vue3 监听鼠标点击拖动事件,移动端滑动事件,页面指针坐标事件

vue3 监听鼠标点击拖动事件,移动端滑动事件,页面指针坐标事件

时间:2024-03-11 11:22:05浏览次数:35  
标签:el startX const 拖动 state 事件 vue3 return event

Pointer Events API 是Hmtl5的事件规范之一,它主要目的是用来将鼠标(Mouse)、触摸(touch)和触控笔(pen)三种事件整合为统一的API。
Pointer指可以在屏幕上反馈一个指定坐标的输入设备。Pointer Event事件和Touch Event API对应的触摸事件类似,它继承扩展了Touch Event,因此拥有Touch Event的常用属性。

Pointer Event Api-整合鼠标事件、触摸和触控笔事件(https://www.cnblogs.com/moqiutao/p/13237093.html)

mdn文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/pointerdown_event

传统监听绑定事件:

<View
    id="carousel"
    class="phone-container"
    :style="{ transform: `translateX(${state.offset}px)`"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
    @touchcancel="handleTouchEnd"
    @mousedown="handleMouseDown"
    @mouseup="handleMouseUp"
    @focusout="handleMouseUp"
    @mouseleave="handleMouseUp"
    @blur="handleMouseUp"
>
</View>


startX: 0,
isDragging: false,
offset: 0,
index: 0,

let banner: HTMLDivElement;
banner = document.querySelector('#carousel') as HTMLDivElement;
 
onMounted
/** 兼容鼠标拖动过程不触发点击事件 */
    setTimeout(() => {
      nextTick(() => {
          banner.addEventListener(
              'click',
              event => {
                  /** 滑动有偏移的话就阻止点击事件的捕获 */
                  if (Math.abs(state.startX - event.clientX) > 5) event.stopPropagation();
              },
              true
          );
      });
  }, 100);

    function handleTouchMove(event: any) {
        if (showDeviceList.value.length === 1) return;

        event.preventDefault();
        const moveX = event.changedTouches[0].clientX;
        const moveLength = moveX - startX;
        state.offset = -state.index * banner.offsetWidth + moveLength;
    }

    function handleTouchStart(event: any) {
        if (showDeviceList.value.length === 1) return;
        startX = event.touches[0].clientX;
        banner.style.transition = '0';
    }

    function handleTouchEnd(event: any) {
        if (showDeviceList.value.length === 1) return;

        const endX = event.changedTouches[0].clientX;
        if (Math.abs(startX - endX) < 50) return autoMove();
        if (startX > endX) {
            state.index < showDeviceList.value.length - 1 && state.index++;
        } else {
            state.index > 0 && state.index--;
        }
        autoMove();
    }

    function handleMouseDown(event) {
        event.preventDefault();
        if (showDeviceList.value.length === 1) return;
        state.startX = event.clientX;
        state.isDragging = true;
        banner.style.transition = '0';
    }
    function handleMouseMove(event) {
        if (!state.isDragging || showDeviceList.value.length === 1) return;
        event.preventDefault();
        const moveX = event.clientX;
        const moveLength = moveX - state.startX;
        state.offset = -state.index * banner.offsetWidth + moveLength;
    }
    function handleMouseUp(event) {
        event.preventDefault();
        if (!state.isDragging || showDeviceList.value.length === 1) return;
        state.isDragging = false;
        const endX = event.clientX;
        if (Math.abs(state.startX - endX) < 50) return autoMove();
        if (state.startX > endX) {
            state.index < showDeviceList.value.length - 1 && state.index++;
        } else {
            state.index > 0 && state.index--;
        }
        autoMove();
    }

    function autoMove() {
        banner.style.transition = '1s';
        state.offset = -state.index * banner.offsetWidth;
        handleTraceExpose('cp_app_cloud_switch_visit');
    }


vue指令事件:页面元素指针坐标事件

<View class="product-outer" :key="state.listUpdated" :class="{ 'one-card': state.list.length === 1 }" v-pointer-event:[state.index]="handleProductChange">
import vPointerEvent from '@/directives/vPointerEvent';

index: Number(sessionStorage.getItem(PRODUCT_INDEX_NAME) || 0), // 所选择产品

function handleProductChange(index: number) {
    state.subIndex = 0;
    state.index = index;
    trace({ id: 'cp_app_pay_product_click' });
    sessionStorage.setItem(PRODUCT_INDEX_NAME, String(index));
}

vPointerEvent.ts

const vPointerEvent = {
    mounted(el: HTMLElement, binding: any) {
        const childNum = el.children.length;
        el.style.width = 'max-content';
        const childWidth = Math.floor(el.clientWidth / childNum);
        const emitIndex = binding.value || (() => {});
        if (childNum == 1) return;

        let startX = 0;
        let offsetX = 0;
        let hasMove = false;
        el.addEventListener('pointerdown', event => {
            startX = event.pageX;
            el.style.transition = '';
        });

        el.addEventListener('pointermove', event => {
            console.log('0000000');
            if (event.pointerType === 'mouse' && event.buttons === 0) return; // 鼠标滑过忽略

            const nowOffsetX = event.pageX - startX;
            if (Math.abs(nowOffsetX) > 10) hasMove = true;
            el.style.transform = `translate3d(${offsetX + nowOffsetX}px, 0px, 0px)`;
        });
        /** 兼容鼠标拖动的滚动事件 */
        el.addEventListener('mouseleave', event => {
            // if (event.pointerType === 'mouse' && event.buttons === 0) return; // 鼠标滑过忽略
            if (!hasMove) return;
            const tempX = offsetX + event.pageX - startX;
            hasMove = false;
            if (tempX > 0) {
                // 右滑超过边界,回弹
                offsetX = 0;
                emitIndex(0);
            } else if (Math.abs(tempX) + childWidth + 100 > el.clientWidth) {
                offsetX = -childWidth * (childNum - 1) + 50;
                emitIndex(childNum - 1);
            } else {
                if (event.pageX - startX === 0) return;
                const isLeftMove = event.pageX - startX < 0;
                const targetIndex = Math[isLeftMove ? 'floor' : 'ceil'](tempX / childWidth);
                offsetX = targetIndex * childWidth + (isLeftMove ? 20 : 20);
                emitIndex(Math.abs(targetIndex));
            }
            el.style.transition = 'all 800ms ease 0s';
            el.style.transform = `translate3d(${offsetX}px, 0px, 0px)`;
        });

        el.addEventListener('pointerup', event => {
            if (!hasMove) return;
            const tempX = offsetX + event.pageX - startX;
            hasMove = false;
            console.log('444444', tempX);
            if (tempX > 0) {
                // 右滑超过边界,回弹
                offsetX = 0;
                emitIndex(0);
            } else if (Math.abs(tempX) + childWidth + 100 > el.clientWidth) {
                offsetX = -childWidth * (childNum - 1) + 50;
                emitIndex(childNum - 1);
            } else {
                if (event.pageX - startX === 0) return;
                const isLeftMove = event.pageX - startX < 0;
                const targetIndex = Math[isLeftMove ? 'floor' : 'ceil'](tempX / childWidth);
                offsetX = targetIndex * childWidth + (isLeftMove ? 20 : 20);
                emitIndex(Math.abs(targetIndex));
            }
            el.style.transition = 'all 800ms ease 0s';
            el.style.transform = `translate3d(${offsetX}px, 0px, 0px)`;
        });

        el.addEventListener('touchmove', event => {
            event.preventDefault();
        });

        if (typeof binding.arg === 'number' && binding.arg > 0) {
            const num = binding.arg;
            offsetX = -num * childWidth + 50;
            emitIndex(Math.abs(num));
            el.style.transform = `translate3d(${offsetX}px, 0px, 0px)`;
        }

        el.addEventListener('click', event => {
            if (hasMove) return;
            const id = (event.target as any)?.id || '';
            if (!id) return;
            const num = Number(id.split('-')?.[1] || 0);
            offsetX = -num * childWidth + 20;
            console.log(num);

            emitIndex(Math.abs(num));
            el.style.transition = 'all 800ms ease 0s';
            el.style.transform = `translate3d(${offsetX}px, 0px, 0px)`;
        });
    }
};

export default vPointerEvent;

标签:el,startX,const,拖动,state,事件,vue3,return,event
From: https://www.cnblogs.com/yoona-lin/p/18065662

相关文章

  • 全屏事件
    //全屏事件handleFullScreen(id){letelement=document.getElementById(id);//需要全屏容器的id//浏览器兼容if(this.fullscreen){//取消全屏if(document.exitFullscreen&&docume......
  • 自定义事件提醒程序
    因为各大软件无法实现每隔自定义固定天数进行事件提醒的功能,在此用Python写了一个简易的Windows端事件提醒弹窗程序。注意没有做界面,只是把事件写死在了程序中,设置为开机自启动,挂在后台一直运行(cpu占用率几乎为0%),到点就会进行弹窗提醒。Step0.环境配置建议新建一个环境,后面用......
  • Vue3学习(二十三)- 保存文档内容正常显示
    写在前面情人节已经接近尾声了,虽然跟我没什么关系,但是我还是很渴望,能遇到一个良人相伴一生。现在时间:内心异常平静,相对吵闹我更喜欢安静的晚上,没人打扰,enjoy自己独处的时间!保存内容显示1、任务拆解读取已保存内容将读取内容在富文本里显示2、读取已保存内容这个很好......
  • Case.1云霄飞车杀人事件
    Case.1云霄飞车杀人事件File.1平成年代的福尔摩斯基本信息:《名侦探柯南》第一话开启了该作品长达30余年的连载登场人物:工藤新一毛利兰毛利小五郎目暮警官琴酒伏特加在本话中,工藤新一的出场伴随着一起案子的圆满解决,他不断展现出了对于推理的热情与当一名侦探的追求,而问......
  • vue3开发文档
    技术要求TypeScriptVue31、用Vue+Vue-Router做一个展示网站。网站按页面划分模块,每个页面按section(部分)再划分模块。培养自己的模块化思想。2、用Vue+Vue-Router+Axios做一个带请求的网站。把请求结果放在页面上展示出来。锻炼请求接口的能力,了解前后端分离思想。3、用Vue+Vu......
  • 【vue3】学习对store中数据的使用
    src/store/modules/nav.jsimport{defineStore}from'pinia';import{handleTree}from'@/utils/ruoyi'import{list}from"@/api/nav/node";conststore=defineStore( 'nav', { state:()=>({ nodeList:[]......
  • Vue3 组合函数拖拽
    代码exportfunctionuseDragMouse(dom,container){letcontainerX=0;letcontainerY=0;letstartX=0;letstartY=0;functiondragPage(e){container.value.style.left=e.pageX-startX+containerX+"px";container.valu......
  • spring-event-事件监听机制实现
    1.事件监听机制概述1.场景模型版本更新了,新版本需要继承老版本的构件分享、自定义属性、着色数据,以后还可能有其他数据要继承,这些数据之间没有直接联系,就是当模型版本变更的时候,他们各自需要执行。2.涉及的三个对象事件源(提供事件处理时的元数据)这里就是模型版本更新了......
  • C#事件(event)的理解
    一、多播委托的应用--观察者模式遇到一个开发的问题?面试者:以面向对象的思想实现一下的场景:猫:Miao一声,紧接着引发了一系列的行为~Miao:引发了一系列的动作;从代码层面来说:代码这样写好吗?猫职责不单一(猫就是猫,他的行为只有Miao一声)依赖太重,依赖了很多的普通类;被依赖的类如......
  • 用Vue3.0 写过组件吗?如果想实现一个 Modal你会怎么设计?
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助一、组件设计组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式现在有一个场景,点击新增与编辑都弹框出来进行填写,功能上大同小异,可能只是标题内容或者是显示的主体内容稍微不同这时候......