【React】事件绑定的细节

发布于:2025-02-27 ⋅ 阅读:(18) ⋅ 点赞:(0)

事件绑定

移动端的click会存在300ms延迟,移动端的click是点击事件,PC端的click是点击。

比如连着点击两下:

  • PC会触发:两次click、一次dbclick
  • 移动端:不回触发click、只会触发dbclick

点击事件:第一次点击后,检测300ms,看看会不会有第二次点击操作,如果没有事单击,如果有就是双击。

render() {
        return <div>
            <button onTouchStart={this.touchstart}
                onTouchMove={this.touchmove}
                onTouchEnd={this.touchend}>
                提交
            </button>
        </div>;
    }

解决方案一:单手指事件模型

在触摸屏设备上,单手指事件模型主要通过 touch 相关的事件来处理。以下是常见的触摸事件:

  • touchstart:当手指触摸屏幕时触发。可以用来记录触摸的开始位置。

  • touchmove:手指在屏幕上滑动时触发。可以用来追踪手指的移动位置。

  • touchend:手指从屏幕上离开时触发。可以用来处理触摸结束后的逻辑。

  • touchcancel:当触摸事件被系统打断时触发,例如,设备出现电话、通知等中断时。

模拟点击效果,可以监听 touchstart 和 touchend 事件。通过判断触摸的起始位置和结束位置,确定是否是点击操作。如果在一定时间内没有滑动,并且触摸的起始和结束位置几乎相同,则可以认为是一个点击。

class Demo extends React.Component {
 
    // 手指按下:记录手指的起始坐标
    touchstart = (ev) => { 
        console.log('startstartstartstartstart')
        let finger = ev.changedTouches[0]; //记录了操作手指的相关信息
        this.touchStartTime = Date.now();
        this.touch = {
            startX: finger.pageX,
            startY: finger.pageY,
            isMove: false
        };
    };
    // 手指移动:记录手指偏移值,和误差值做对比,分析出是否发生移动
    touchmove = (ev) => {
        console.log('movemovemovemove')
        let finger = ev.changedTouches[0],
            { startX, startY } = this.touch;
        let changeX = finger.pageX - startX,
            changeY = finger.pageY - startY;
        if (Math.abs(changeX) > 10 || Math.abs(changeY) > 10) {
            this.touch.isMove = true;
        }
    };
    // 手指离开:根据isMove判断是否是点击
    touchend = () => {
        console.log('endddddd')
        this.touchEndTime = Date.now();
        console.log(this.touch.isMove, 'this.touch.isMove')
        // 点击操作时间是否小于300ms
        if (this.touchEndTime - this.touchStartTime < 300) {
            this.touch.isMove = false;
        }  
        let { isMove } = this.touch;
        if (isMove) return;
        // 说明触发了点击操作
        console.log('点击了按钮');
    };
}    

解决方案二:fastclick(已过时,仍可用)

使用fastclick插件解决移动端使用click事件的300ms延迟问题,在入口文件导入。注意:可能与其他库或框架冲突

import FastClick from "fastclick"
FastClick.attach(document.body)
handle = ()=>{
  ....
}

render() {
        return <div>
            <button onClick={this.handle}>
                提交
            </button>
        </div>;
    }

解决方案三:CSS touch-action属性

touch-action 属性允许开发者控制浏览器对触摸手势的默认行为。 将 touch-action 设置为none可以阻止浏览器对触摸事件的默认处理,包括双击缩放,从而消除 300ms 延迟。

循环事件绑定

在React中,我们给循环「创建」的元素做“循环事件绑定”,是好还是不好?
按常理来说,此类需求用事件委托处理是最好的,但是在React 中,我们循环给元素绑定的合成事件本身就是基于事件委托处理的,所以无需我们自己再单独的设置事件委托的处理机制

class Demo extends React.Component {
    state = {
        arr: [{
            id: 1,
            title: '新闻'
        }, {
            id: 2,
            title: '体育'
        }, {
            id: 3,
            title: '电影'
        }]
    };

    handle = (item) => {
        // item:点击这一项的数据
        console.log('我点击的是:' + item.title);
    };

    render() {
        let { arr } = this.state;
        return <div>
            {arr.map(item => {
                let { id, title } = item;
                return <span key={id}
                    style={{
                        padding: '5px 15px',
                        marginRight: 10,
                        border: '1px solid #DDD',
                        cursor: 'pointer'
                    }}
                    onClick={this.handle.bind(this, item)}>
                    {title}
                </span>;
            })}
        </div>;
    }
}

在vue中,给当前元素添加事件绑定就是给给它做事件绑定,我们可以给它父级元素做事件委托,根据事件源判断点击的是哪一个

<template>
  <div class="list-container" @click="handleClick">
    <div class="item" v-for="(item, index) in items" :key="index">
      {{ item }}
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      items: ['Item 1', 'Item 2', 'Item 3', 'Item 4']
    };
  },
  methods: {
    handleClick(event) {
      // 获取事件源
      const clickedElement = event.target;

      // 判断点击的是哪个子元素(例如列表项)
      if (clickedElement && clickedElement.classList.contains('item')) {
        // 获取点击的列表项的文本内容
        const clickedItem = clickedElement.textContent;
        console.log(`点击了: ${clickedItem}`);
      }
    }
  }
}
</script>