我的反应有问题。我正在尝试实现一个简单的可滚动 div,其中包含许多子 div,可通过水平滚动查看。
基本上每个children div对应一天。用户在第一次查看有关当天和接下来几天的信息时加载该组件。但是,如果用户滚动(向左或向右),我希望能够附加更多信息,实现一种“无限滚动功能”。
当我尝试在父 div 的末尾附加新的子 div 时,我一点问题都没有。但是,当我尝试在父 div 的开头添加新的子项时(例如,用户希望看到前几天),在添加新元素后,滚动会发生变化,导致用户对滚动发生变化的原因感到困惑。
我创建了一个小的 JS fiddle 来复制我的设置。尝试单击“向左添加”,您将看到当前的行为。 有没有办法在不移动整个视图的情况下添加新元素? https://jsfiddle.net/k75pvey3/3/
附言我在网上看到很多关于这个问题的答案。但是,我看到的所有这些都假设新组件具有特定宽度。在我的例子中(正如我试图在小提琴中展示的那样)我无法确定哪个是新添加的子 div 的宽度。
参考这里是代码:
function App(props) {
const [array, setArray] = React.useState(['100', '321', '32', '412', '12', '33', '54'])
const addLeft = () => {
setArray([Math.floor(Math.random()*300), ...array])
}
const addRight = () => {
setArray([...array, Math.floor(Math.random()*300)])
}
return (
<div className='App'>
<button onClick={addLeft}>add left</button>
<button onClick={addRight}>add right</button>
<div className="container">
{array.map(i => (<div className="element" style={{minWidth:i}}>{i}</div>))}
</div>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#app"))
这是CSS:
.container {
background-color: red;
width: 550px;
height: 120px;
margin: auto;
display: flex;
overflow: auto;
}
.element {
height: 100px;
background-color: yellow;
margin: 10px;
font-size: 30px;
color: black;
display: flex;
}
我有一个坏消息要告诉你,这通常是关于虚拟列表的复杂部分之一——在滚动轴的开头添加一个新元素,同时保持滚动位置。
react-virtualized
或react-window
。
如果您不想使用现有的图书馆,一种解决方案是您可以收听
width
内内容的div
(例如Element.scrollWidth
),然后通过设置来补偿它.scrollLeft
容器的价值。但是,当您在滚动时加载时它会变得复杂,因为滚动可能是“带有惯性”的,尤其是在触摸屏设备/笔记本电脑上的触摸板上。
(根据经验,当我过于自信时,我可以自己编写一个虚拟列表,最终由于很多边缘情况而使用库)
您可以使用
ref
来控制父母。
ref.current.scrollBy
滚动所需的像素数量。
您可以使用另一个 ref 来获取添加元素的实际宽度,但在您的示例中,我们可以只使用该随机数
const { useState, useRef } = React;
function App(props) {
const prnt = useRef();
const [array, setArray] = React.useState(['100', '321', '32', '412', '12', '33', '54'])
const addLeft = () => {
const newWidth = Math.floor(Math.random()*300);
setArray([ newWidth, ...array])
prnt.current.scrollBy(newWidth - 20, 0)
}
const addRight = () => {
setArray([...array, Math.floor(Math.random()*300)])
}
return (
<div className='App'>
<button onClick={addLeft}>add left</button>
<button onClick={addRight}>add right</button>
<div className="container" ref={prnt}>
{array.map(i => (<div className="element" style={{minWidth:i}}>{i}</div>))}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("react"));
body {
background: transparent; /* Make it white if you need */
padding: 0 24px;
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.App {
color: #72a24d;
}
.container {
background-color: red;
width: 550px;
height: 120px;
margin: auto;
display: flex;
overflow: auto;
}
.element {
height: 100px;
background-color: yellow;
margin: 10px;
font-size: 30px;
color: black;
display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>