如何仅在 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 专用属性,即 onMouseDown
、onMouseMove
、onMouseUp
.在您的情况下,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>
);
}
我正在使用此代码作为基础在 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 专用属性,即 onMouseDown
、onMouseMove
、onMouseUp
.在您的情况下,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>
);
}