如何在 react-draggable 拖拽时避免误触发内容中的 click 事件

2,263 阅读2分钟

我正在参加「掘金·启航计划」

概述

如题,今天在处理 “拖拽” 时,遇到的一个小问题

<Draggable>
  <button onClick={handleClick}>我是一个可拖拽的按钮</button>
</Draggable>

上述代码,在使用 react-draggable 库(目前用的是 "react-draggable": "^4.4.5" 的版本 )实现拖拽时,一旦拖拽结束,就会误触被 <Draggable> 包裹的元素中的 click 事件

解决方案

通过手动维护一个“是否处于拖拽状态”的标识来做判断,详情可见:线上 Demo (PS:这个好像需要科学上网)

演示

如上图,在拖拽的时候虽然也触发了包裹的元素中的 click 事件,但因为我们手动维护一个 isDragging 的标识(“是否处于拖拽状态”),这样我们就可以按需执行我们的 click 逻辑

代码

import * as React from 'react';
import Draggable from 'react-draggable';

import './style.css';

export default function App() {
  let isDragging = false;

  const handleDrag = () => {
    isDragging = true;
  };
  const handleStop = () => {
    console.log('handleStop');

    // 触发 onStop 后会触发 onClick,加个 setTimeout 是为了让修改不“马上”发生,导致 handleClick 拿到的不是预期的结果
    setTimeout(() => (isDragging = false), 0);
  };

  const handleClick = () => {
    console.log('handleClick');

    if (isDragging) {
      return;
    }

    console.log('啊,我被 click 了');
  };

  return (
    <div>
      <p>react-draggable 拖拽时规避误触发内容中的 click 事件</p>

      <Draggable onDrag={handleDrag} onStop={handleStop}>
        <button onClick={handleClick}>我是一个可拖拽的按钮</button>
      </Draggable>
    </div>
  );
}

还是贴一下代码吧,避免有些朋友科学上网不便 ( ̄3 ̄)a

对了,顺便想给 码上掘金 提个小建议,个人感觉现在 码上掘金 的功能还是不够全面,基本只能写传统 JS 代码,想引入第三方库或者使用React、Vue 时一运行就报错~

个人体验了比较多个线上代码平台,感觉 stackblitz 会相对好用一点,但要科学上网,而且也不能像 码上掘金 直接嵌套进掘金的文章当中。有好几次都想用 码上掘金 写,但最终都是被其相对不是很好用的情况劝退了 ( ̄. ̄)

言归正传,上述代码中比较关键的是 setTimeout(() => (isDragging = false), 0); 这一步,我们简单说明一下:

  1. handleDraghandleStophandleClick,这三个函数会依次执行
  2. handleDrag 中设置 isDragging = true;
  3. 如果在 handleStop 直接设置 isDragging = false; 的话,等到 handleClick 执行时,isDragging 的值将会是 false,这样并不符合我们的预期
  4. 所以要通过 setTimeout(() => (isDragging = false), 0); 将其变成一个异步调用,这样,在 handleClick 执行时,isDragging 的值还是 true,符合我们的预期