我制作了这个水平滑动器,它可以左右滚动,但是当我尝试左右拖动时它什么也没做。我希望能够左右滚动和左右拖动。
如果我向左或向右滚动,然后移动光标,它会一直向左滚动。
import React, { useRef, useState, useEffect } from "react";
export default function Swiper() {
const ref = useRef(null);
const [startX, setStartX] = useState<number>(0);
const [startScrollLeft, setStartScrollLeft] = useState<number>(0);
const [myMouseDown, setMyMouseDown] = useState<boolean>(false);
const handleDown = (e: any) => {
console.log("down");
if (!ref.current.contains(e.target)) return;
setMyMouseDown(true);// <=============================== This makes it true
setStartX(e.pageX - ref.current.offsetLeft);
setStartScrollLeft(ref.current.scrollLeft);
};
const handleMove = (e: any) => {
console.log(myMouseDown);// Why this always false when I mouse down and move?
e.preventDefault();
if (!ref.current.contains(e.target)) return;
const mouseX = e.pageX - ref.current.offsetLeft;
const moveX = mouseX - startX;
if (myMouseDown) {
console.log("move"); // <==================================== never fires!
ref.current.scrollLeft = startScrollLeft - moveX;
}
};
const handleUp = () => {
console.log("up");
setMyMouseDown(false); // <=========================== This makes it false
};
useEffect(() => {
document.addEventListener("mouseup", handleUp);
document.addEventListener("mousedown", handleDown);
document.addEventListener("mousemove", handleMove);
return () => {
document.removeEventListener("mouseup", handleUp);
document.removeEventListener("mousedown", handleDown);
document.removeEventListener("mousemove", handleMove);
};
}, []);
const handleScroll = (e: any) => {
const { scrollWidth, scrollLeft, clientWidth } = e.target;
if (scrollLeft + clientWidth === scrollWidth) console.log("end");
if (scrollLeft === 0) console.log("start");
};
return (
<header className="container">
{startX} - {startScrollLeft} - {JSON.stringify(myMouseDown)}
<ul onScroll={handleScroll} ref={ref}>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
<style jsx>{`
ul {
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
height: 260px;
cursor: grab;
padding: 0;
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(8, 260px);
}
ul::-webkit-scrollbar {
background: #ebeced;
height: 6px;
margin: 0 20px;
}
ul::-webkit-scrollbar-thumb {
background: #c8cad0;
}
li {
display: inline-block;
vertical-align: top;
width: 230px;
height: 230px;
white-space: normal;
background: grey;
}
`}</style>
</header>
);
}
答案 0 :(得分:1)
您需要更新 useEffect
钩子中的依赖项:
useEffect(() => {
document.addEventListener("mouseup", handleUp);
document.addEventListener("mousedown", handleDown);
document.addEventListener("mousemove", handleMove);
return () => {
document.removeEventListener("mouseup", handleUp);
document.removeEventListener("mousedown", handleDown);
document.removeEventListener("mousemove", handleMove);
};
}, [handleDown, handleMove]);
然后您需要在处理程序中使用 useCallback 钩子:
const handleDown = useCallback((e: any) => {
console.log("down");
setMyMouseDown(true); // <=============================== This makes it true
if (!ref.current.contains(e.target)) return;
setStartX(e.pageX - ref.current.offsetLeft);
setStartScrollLeft(ref.current.scrollLeft);
}, []);
const handleMove = useCallback(
(e: any) => {
e.preventDefault();
console.log("myMouseDown", myMouseDown); // Why this always false when I mouse down and move?
if (!ref.current.contains(e.target)) return;
const mouseX = e.pageX - ref.current.offsetLeft;
const moveX = mouseX - startX;
if (myMouseDown) {
console.log("move"); // <==================================== never fires!
ref.current.scrollLeft = startScrollLeft - moveX;
}
},
[myMouseDown, startScrollLeft, startX]
);
工作代码:https://codesandbox.io/s/pedantic-sanne-mfp9i?file=/src/App.tsx
顺便说一句。 在每个事件上设置状态是次优的。你应该在这里使用 useRef 而不是 useState :
const startX = useRef<number>(0);
startX.current = e.pageX - ref.current.offsetLeft;
const moveX = mouseX - startX.current;