Javascript 无法实现复杂的滚动行为
在我正在开发的一个应用程序中,我面临着一个相当棘手的问题,我的头撞在桌子上已经有一段时间了,现在我正试图解决这个问题。任何提示都将不胜感激 基本上,我有一个容器,其中包含许多元素;如此之多以至于它们溢出,容器滚动。在容器中有一个特殊的元素,我总是想要在容器的中间——即使物品被连续地添加到它上面和下面。我已经做到了这一点,但是,这里有一个陷阱:一旦用户手动滚动这个容器,我想禁用之前的行为,其中一个特殊的项目仍然在容器的中心,这是我无法做到的 下面是我实现这一示例的最佳尝试,这里是一个链接。我的实现的工作方式是,我有一个容器,其中包含从一个数组呈现的项目列表,然后是“特殊项目”,然后是从另一个数组呈现的更多项目。安装组件时,我运行两个函数:Javascript 无法实现复杂的滚动行为,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,在我正在开发的一个应用程序中,我面临着一个相当棘手的问题,我的头撞在桌子上已经有一段时间了,现在我正试图解决这个问题。任何提示都将不胜感激 基本上,我有一个容器,其中包含许多元素;如此之多以至于它们溢出,容器滚动。在容器中有一个特殊的元素,我总是想要在容器的中间——即使物品被连续地添加到它上面和下面。我已经做到了这一点,但是,这里有一个陷阱:一旦用户手动滚动这个容器,我想禁用之前的行为,其中一个特殊的项目仍然在容器的中心,这是我无法做到的 下面是我实现这一示例的最佳尝试,这里是一个链接。我的
center
和updater
center
初始将特殊项居中,更新程序开始每隔一段时间使用setInterval
将项添加到两个数组中。每次将项目添加到其中一个数组时,都会再次运行center
,以使特殊项目在其父容器中居中。到目前为止,这可以完美地保持特殊项目居中
为了禁用这种居中行为,我有一个初始状态为false
的布尔值,称为hasScrolled
,还有一个附加到主容器onWheel事件的事件侦听器,名为userScrollHandler
,它将hasScrolled
设置为true
。我的center
函数仅在hasScrolled
为false时将特殊项目居中,因此理论上,一旦用户滚动,hasScrolled
将为true
,然后居中行为将停止。不幸的是,这似乎不起作用。我确信,当用户滚动容器时(打开控制台查看每个滚动上的日志),会调用这两个事件,hasScrolled
被设置为true
。出于某种原因,center
函数认为hasScrolled
为false。我尝试过许多其他的事情,比如将这些值传递给中心
函数,不让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);
import React,{useState,useffect,useRef,useReducer}来自“React”;
从“react dom”导入react dom;
常量项1=[];
for(设i=0;i<10;i++){
项目1.推动(“顶部”);
}
常量项2=[];
for(设i=0;i<10;i++){
项目2.推动(“底部”);
}
常量应用=()=>{
const[hasScrolled,setHasScrolled]=useState(false);
const[tops,addTopItem]=useReducer(state=>{
const stateCopy=[…state];
stateCopy.push(Math.random());
返回状态副本;
},项目1);
const[bottoms,addBottomItem]=useReducer(state=>{
const stateCopy=[…state];
stateCopy.unshift(Math.random());
返回状态副本;
},第2项);
const middle=useRef(null);
const container=useRef(null);
常数中心=()=>{
如果(有麻烦)返回;
container.current.scrollTo(
0,
中电流偏置-
container.current.offsetTop-
container.current.clientHeight/2
);
};
常量更新程序=()=>{
设置间隔(()=>{
addTopItem();
if(container.current&&middle.current)center();
}, 500);
设置间隔(()=>{
addBottomItem();
if(container.current&&middle.current)center();
}, 700);
};
const userScrollHandler=e=>{
日志(“用户滚动”);
setHasScrolled(真);
};
useffect(()=>{
中心();
更新程序();
}, []);
返回(
{tops.map((项目,idx)=>{
返回(
{item}
);
})}
中间的
{bottoms.map((item,idx)=>{
返回(
{item}
);
})}
);
};
常量集装箱样式={
边距:“0自动”,
玛金托普:“10vh”,
高度:“400px”,
宽度:“300px”,
背景:“eee”,
溢出:“自动”
};
const itemStyle={
宽度:“100%”,
高度:“40px”,
边框底部:“1px纯蓝”,
显示:“flex”,
辩护内容:“中心”,
对齐项目:“中心”
};
常量middleItemStyle={…itemStyle};
middleItemStyle.background=“lime”;
const rootElement=document.getElementById(“根”);
render(,rootElement);
能否使中间元素独立,而不渲染它
{hasScrolled && <div ref={middle} style={middleItemStyle}>
Middle
</div>}
{hasscrowled&&
中间的
}
能否使中间元素独立,而不渲染它
{hasScrolled && <div ref={middle} style={middleItemStyle}>
Middle
</div>}
{hasscrowled&&
中间的
}
不幸的是,没有,因为如果用户回滚到该项目,该项目应该仍然存在。或者,如果他们只是滚动一点点,使它仍然在屏幕上,它不应该消失。知道我的方法为什么不起作用吗?不幸的是,不知道,因为如果用户回滚到该项,该项应该仍然存在。或者,如果他们只是滚动一点点,使它仍然在屏幕上,它不应该消失。知道为什么我的方法不起作用吗?