我在我正在开发的应用程序中遇到了一个非常棘手的问题,并且已经在我的桌子上敲打了一段时间,试图解决它。任何提示将不胜感激!
基本上,我有一个容器,里面包含许多元素;太多了,以至于它们溢出,容器滚动。容器中有一个特殊的元素,我希望它始终位于容器的中间 -即使项目不断添加到容器的上方和下方。我已经实现了这个目标,但是,这里有一个问题:一旦用户手动滚动此容器,我想禁用以前的行为,即一个特殊项目保留在容器的中心,而我无法做到这一点。
下面是我实现示例的最佳尝试,这里是我尝试的代码沙箱的链接。我的实现方式是我有一个容器,其中包含从数组渲染的项目列表,然后是"特殊项目",然后是从不同数组渲染的更多项目。当组件挂载时,我运行两个函数:center
和updater
。center
最初将特殊项目居中,更新程序开始每隔一段时间向两个数组添加项目,setInterval
.每次将项目添加到其中一个数组时,都会再次运行center
以使特殊项目在其父容器中居中。到目前为止,这可以完美地保持特殊项目的中心。
为了禁用这种居中行为,我有一个最初false
称为状态hasScrolled
的布尔值,以及一个附加到主容器的 onWheel 事件的 onWheel 事件,称为userScrollHandler
将hasScrolled
设置为true
。我的center
函数仅在hasScrolled
为假时才居中特殊项目,因此理论上一旦用户滚动,hasScrolled
就会true
,然后居中行为将停止。不幸的是,这似乎不起作用。我肯定当用户滚动容器时都会调用该事件(打开控制台以查看每次滚动的日志),并且hasScrolled
被设置为true
。出于某种原因,center
函数认为hasScrolled
是假的。我已经尝试了许多其他事情,例如将这些值传递给center
函数,不hasScrolled
保持状态,只是让它成为相关变量,使用上下文等。我不知道如何做到这一点以及为什么我的实现都不起作用。有人知道如何做到这一点或我做错了什么?
我的实现:
import React, { useState, useEffect, useRef, useReducer } from "react";
import ReactDOM from "react-dom";
const items1 = [];
for (let i = 0; i < 10; i++) {
items1.push("top");
}
const items2 = [];
for (let i = 0; i < 10; i++) {
items2.push("bottom");
}
const App = () => {
const [hasScrolled, setHasScrolled] = useState(false);
const [tops, addTopItem] = useReducer(state => {
const stateCopy = [...state];
stateCopy.push(Math.random());
return stateCopy;
}, items1);
const [bottoms, addBottomItem] = useReducer(state => {
const stateCopy = [...state];
stateCopy.unshift(Math.random());
return stateCopy;
}, items2);
const middle = useRef(null);
const container = useRef(null);
const center = () => {
if (hasScrolled) return;
container.current.scrollTo(
0,
middle.current.offsetTop -
container.current.offsetTop -
container.current.clientHeight / 2
);
};
const updater = () => {
setInterval(() => {
addTopItem();
if (container.current && middle.current) center();
}, 500);
setInterval(() => {
addBottomItem();
if (container.current && middle.current) center();
}, 700);
};
const userScrollHandler = e => {
console.log("user scrolled");
setHasScrolled(true);
};
useEffect(() => {
center();
updater();
}, []);
return (
<div ref={container} onWheel={userScrollHandler} style={containerStyle}>
{tops.map((item, idx) => {
return (
<div key={idx} style={itemStyle}>
{item}
</div>
);
})}
<div ref={middle} style={middleItemStyle}>
Middle
</div>
{bottoms.map((item, idx) => {
return (
<div key={idx} style={itemStyle}>
{item}
</div>
);
})}
</div>
);
};
const containerStyle = {
margin: "0 auto",
marginTop: "10vh",
height: "400px",
width: "300px",
background: "#eee",
overflow: "auto"
};
const itemStyle = {
width: "100%",
height: "40px",
borderBottom: "1px solid blue",
display: "flex",
justifyContent: "center",
alignItems: "center"
};
const middleItemStyle = { ...itemStyle };
middleItemStyle.background = "lime";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
你能让中间元素独立而不渲染它吗?
{hasScrolled && <div ref={middle} style={middleItemStyle}>
Middle
</div>}