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&&
中间的
}

不幸的是,没有,因为如果用户回滚到该项目,该项目应该仍然存在。或者,如果他们只是滚动一点点,使它仍然在屏幕上,它不应该消失。知道我的方法为什么不起作用吗?不幸的是,不知道,因为如果用户回滚到该项,该项应该仍然存在。或者,如果他们只是滚动一点点,使它仍然在屏幕上,它不应该消失。知道为什么我的方法不起作用吗?