防止双击被解释为两次单击?

IT技术 javascript reactjs onclick event-handling dom-events
2021-05-11 05:46:25

我有以下相当简单的 React 类:

import React from "react"

export default class DoubleClick extends React.Component {  

  constructor(props) {
    super(props);
    this.state = {
    };
    this.handleClick = this.handleClick.bind(this);
    this.handleDoubleClick = this.handleDoubleClick.bind(this);
  }
  handleClick() {
    console.log("Click");
  }
  handleDoubleClick() {
    console.log("Double Click");
  }
  render() {
    return (
      <div style={{backgroundColor: 'pink'}}>
          <div onClick={this.handleClick}> 
            <span onDoubleClick={this.handleDoubleClick}> Hello </span> 
            <span onDoubleClick={this.handleDoubleClick}> world. </span>
          </div>
      </div>
    );
  }
} 

当有人单击外部 div 时,我想调用handleClick,当有人双击我想调用的任何内部跨度时,我想调用handleDoubleClick,而不是handleClick外部 div 的 。

但是,每当我双击时,handleDoubleClick()被调用, handleClick也被调用,即两次。

我想打电话给handleClick()只有当我点击,但这样做双击-这可能吗?

2个回答

我有一个 HOC,我用它来近似您正在寻找的内容:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class DoubleClick extends Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onDoubleClick = this.onDoubleClick.bind(this);
    this.timeout = null;
  }

  onClick(e) {
    e.preventDefault();

    if(this.timeout === null) {
      this.timeout = window.setTimeout(() => {
        this.timeout = null;
        this.props.onClick();
      }, 300);
    }
  }

  onDoubleClick(e) {
    e.preventDefault();
    window.clearTimeout(this.timeout);
    this.timeout = null;
    this.props.onDoubleClick();
  }

  render() {
    const { onClick, onDoubleClick, children, ...childProps } = this.props;
    const props = Object.assign(childProps, { onClick: this.onClick, onDoubleClick: this.onDoubleClick });
    return React.cloneElement(children, props);
  }
}

DoubleClick.propTypes = {
  onClick: PropTypes.func.isRequired,
  onDoubleClick: PropTypes.func.isRequired,
  children: PropTypes.element.isRequired,
};

像这样使用:

<DoubleClick onClick={clickHandler} onDoubleClick={doubleClickHandler}>
  <button>Click or double click me</button>
</DoubleClick>

当收到第一次点击时,它会设置一个 300 毫秒的超时时间。如果在 300ms 内没有收到第二次点击,onClickprop 中的函数将被调用。如果在 300 毫秒内收到第二次点击,onDoubleClick将调用 prop 中的函数,并取消超时,因此onClick不会触发。

毋庸置疑,这是一个不完美的近似值,但我发现它在实践中是一种足够令人满意的用户体验。

就像其他人所说的那样,不可能在没有超时的情况下在父级上执行单击事件,而在子级上执行 doubleClick 事件(我认为)。

如果您可以牺牲 500 毫秒的 UX 部分,直到点击被识别为非双击,您可以使用超时。

constructor(props) {
    super(props);
    this.state = {
    };
    this.handleClick = this.handleClick.bind(this);
    this.handleDoubleClick = this.handleDoubleClick.bind(this);

    // hack doubleclick
    this.doubleClickTimeout = 500; // default doubleclick timeout
    this.clickedTimeout = null;
  }
  handleClick(ev) {
    if (!this.clickedTimeout) {
      this.clickedTimeout = setTimeout(() => {
        this.clickedTimeout = null;
        // do your stuff here
        console.log('Clicked');
      }, this.doubleClickTimeout);
    }


  }
  handleDoubleClick() {
    clearTimeout(this.clickedTimeout);
    this.clickedTimeout = null;
    console.log("Double Click");

  }
  render() {
    return (
      <div style={{backgroundColor: 'pink'}}>
          <div onClick={this.handleClick}>
            <span onDoubleClick={this.handleDoubleClick}> Hello </span>
            <span onDoubleClick={this.handleDoubleClick}> world. </span>
          </div>
      </div>
    );
  }