如何仅在 React 中的特定组件内监听事件?

How to listen an event only within a specific component in React?

我正在使用此代码作为基础在 ReactJS 中创建一个可触摸的滑块,以便用户可以用手指更改滑块,它工作正常,但是我需要仅在轮播内触发事件( track div),这里没有发生什么。在此示例中,事件从屏幕的任何部分触发(您可以在蓝色部分尝试)。

有什么方法可以做到这一点,让事件监听器只在特定组件内工作(这里只是一个 div)?

记住,我使用的是 React,这只是一个示例。

const track = document.querySelector('.track');
let initialPosition = null;
let moving = false;
let transform = 0;

const gestureStart = (e) => {
  initialPosition = e.pageX;
  moving = true;
  const transformMatrix = window.getComputedStyle(track).getPropertyValue('transform');
  if (transformMatrix !== 'none') {
    transform = parseInt(transformMatrix.split(',')[4].trim());
  }
}

const gestureMove = (e) => {
  if (moving) {
    const currentPosition = e.pageX;
    const diff = currentPosition - initialPosition;
    track.style.transform = `translateX(${transform + diff}px)`;  
  }
};

const gestureEnd = (e) => {
  moving = false;
}

if (window.PointerEvent) {
  window.addEventListener('pointerdown', gestureStart);

  window.addEventListener('pointermove', gestureMove);

  window.addEventListener('pointerup', gestureEnd);  
} else {
  window.addEventListener('touchdown', gestureStart);

  window.addEventListener('touchmove', gestureMove);

  window.addEventListener('touchup', gestureEnd);  
  
  window.addEventListener('mousedown', gestureStart);

  window.addEventListener('mousemove', gestureMove);

  window.addEventListener('mouseup', gestureEnd);  
}
body {
  margin: 0;
}
.carousel {
  width: 100vw;
  height: 100vh;
  background: blue;
  position: relative;
  overflow: hidden;
  
}
.carousel .track {
  position: absolute;
  top: 50px;
  left: 10px;
  display: inline-flex;
  touch-action: none;
}

.carousel .track .card {
  width: 100px;
  height: 100px;
  background: #fff;
  border-radius: 3px;
  margin-right: 20px;
}

h2 {
  color: white;
  text-align: center;
}
<div class="container">
  <div class="carousel">
    <h2>It shouldn't work here outside of the carousel</h2>
    <div class="track">
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
    </div>
  </div>
</div>

您可以将事件侦听器添加到任何 dom 元素,而不仅仅是 window。比如你在这里打开一个控制台,你可以这样做:

document.querySelector('#left-sidebar').addEventListener('mousemove', e => console.log(e))

这将仅记录页面左侧导航栏上的移动。

对于 React 组件,您可以使用 ref 获取对 dom 元素的引用,并使用 useEffect 附加侦听器。示例:

import { useEffect, useRef } from "react";

export default function App() {
  const ref = useRef();
  useEffect(() => {
    ref.current.addEventListener("mousemove", (e) => {
      console.log("moving in the blue box", e.x, e.y);
    });
  }, []);
  return (
    <div className="App">
      <div ref={ref} style={blueBox} />
      <div style={orangeBox} />
    </div>
  );
}

const box = { minWidth: "300px", minHeight: "300px" };
const blueBox = { ...box, backgroundColor: "cornflowerblue" };
const orangeBox = { ...box, backgroundColor: "coral" };

在 React 中将事件侦听器附加到特定 DOM 元素的最佳且最安全的方法是使用 JSX 专用属性,即 onMouseDownonMouseMoveonMouseUp.在您的情况下,React 组件必须如下所示:

export default function App() {

  /**
   * This is where you must define your listeners: 
   * gestureStart, gestureMove, gestureEnd
   *
   */


  return (
    <div className="container">
      <div className="carousel">
        <h2>It shouldn't work here outside of the carousel</h2>
        <div
          onMouseDown={gestureStart}
          onMouseMove={gestureMove}
          onMouseUp={gestureEnd}
          className="track"
        >
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
        </div>
      </div>
    </div>
  );
}

您正在将事件添加到 window,这就是全部,仅将它们添加到跟踪


xport default function App() {
const track = React.useRef();
  /**
   * This is where you must define your listeners: 
   * onMouseDown, gestureMove, gestureEnd
   *
   */
 
React.useEffect(()=>{

if (window.PointerEvent && track.current) {
  track.current.addEventListener('pointerdown', gestureStart);

  track.current.addEventListener('pointermove', gestureMove);

  track.addEventListener('pointerup', gestureEnd);  
} else {
  track.addEventListener('touchdown', gestureStart);

  track.addEventListener('touchmove', gestureMove);

  track.addEventListener('touchup', gestureEnd);  
  
  track.addEventListener('mousedown', gestureStart);

  track.addEventListener('mousemove', gestureMove);

  track.addEventListener('mouseup', gestureEnd);  
}

},[]);

  return (
    <div className="container">
      <div className="carousel">
        <h2>It shouldn't work here outside of the carousel</h2>
        <div
          ref={track}
        >
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
          <div className="card"></div>
        </div>
      </div>
    </div>
  );
}