滚动到 React 中溢出的 div 的底部

IT技术 javascript html css reactjs
2021-04-25 14:18:31

我有ul一个max-heightoverflow-y: auto

当用户输入足够多的li元素时,ul开始滚动,但我希望最后一个li带有 的元素form始终存在并且用户可以查看。

我试过实现一个scrollToBottom看起来像这样函数:

scrollToBottom() {
    this.formLi.scrollIntoView({ behavior: 'smooth' });
}

但这只会ul跳转到屏幕顶部,并将li其中的表单显示为唯一可见的东西。

有没有更好的方法来实现这一点?我发现的答案往往有点旧并且使用 ReactDOM。谢谢!

CSS:

.prompt-box .options-holder {
    list-style: none;
    padding: 0;
    width: 95%;
    margin: 12px auto;
    max-height: 600px;
    overflow-y: auto;
}

HTML:

<ul className='options-holder'>
    {
        this.state.items.map((item, index) => (
            <li key={item.id} className={`option ${index === 0 ? 'first' : ''}`}>
                <div className='circle' onClick={this.removeItem} />

                <p className='item-text'>{ item.text }</p>
            </li>
        ))
    }

    <li key={0} className={`option form ${this.state.items.length === 0 ? 'only' : ''}`} ref={el => (this.formLi = el)}>
        <div className='circle form' />

        <form className='new-item-form' onSubmit={this.handleSubmit}>
            <input 
                autoFocus 
                className='new-item-input' 
                placeholder='Type something and press return...' 
                onChange={this.handleChange} 
                value={this.state.text}
                ref={(input) => (this.formInput = input)} />
        </form>
    </li> 
</ul>
4个回答

我有一个填充页面高度的容器。此容器具有显示 flex 和 flex 方向列。然后我有一个Messages组件,它是ul 一个li每条消息加上一个特殊AlwaysScrollToBottom组件作为最后一个子组件,在 的帮助下useEffect,滚动到列表底部。

const AlwaysScrollToBottom = () => {
  const elementRef = useRef();
  useEffect(() => elementRef.current.scrollIntoView());
  return <div ref={elementRef} />;
};

const Messages = ({ items }) => (
  <ul>
    {items.map(({id, text}) => <li key={id}>{text}</li>)}
    <AlwaysScrollToBottom />
  </ul>
)

const App = () => (
  <div className="container">
    <Messages items={[...]}>
    <MessageComposer />
  </div>
)

CSS是

.container {
  display: flex;
  height: 100vh;
  flex-direction: column;
}

ul {
  flex-grow: 1;
  overflow-y: auto;
}

MessageComposer 为简洁起见已省略,它包含用于发送消息的表单、输入字段等。

使用react滚动库。但是,您必须明确设置您的ul.

import { animateScroll } from "react-scroll";

scrollToBottom() {
    animateScroll.scrollToBottom({
      containerId: "options-holder"
    });
}

您可以调用scrollToBottomsetState 回调。

例如

this.setState({ items: newItems}, this.scrollToBottom);

或者通过使用 setTimeout。

或者您甚至可以设置Elementfromreact-scroll并滚动到某个li.

在渲染来自用户导入的组件数组时,我遇到了类似的问题。我最终使用 componentDidUpdate() 函数来让我的工作。

componentDidUpdate() {
        // I was not using an li but may work to keep your div scrolled to the bottom as li's are getting pushed to the div
        const objDiv = document.getElementById('div');
        objDiv.scrollTop = objDiv.scrollHeight;
      }

似乎您正在构建一个类似聊天的界面。您可以尝试将<ul>包装div.circle-form在一个单独的 div 中,如下所示:

ul{
  border:1px solid red;
  height:13em;
  overflow-y:auto;
  position:relative;
}
ul li{
  border-bottom:1px solid #ddd;
  list-style:none;
  margin-left:0;
  padding:6px;
}

.wrapper{
  background:#eee;
  height:15em;
  position:relative;
}
.circle-form{
  background:#ddd;
  height:2em;
  padding:3px;
  position:absolute;
  bottom:0;
  left:0;
  right:0;
  z-index:2;
}
.circle-form input[type=text]{
  padding:8px;
  width:50%;
}
<div class="wrapper">
   <ul id="list">
       <li>item</li>
       <li>item</li>
       <li>item</li>
       <li>item</li>
       <li>item</li>
       <li>item</li>
       <li>item</li>
       <li>item</li>
    </ul>
    <div class="circle-form">
        <input type="text" name="type_here" placeholder="Enter something..." autofocus/>
    </div>
</div>

编辑

并使用 javascript 滚动到列表底部

var list = document.getElementById("list");
list.scrollTop = list.offsetHeight;