React 滚动盒子:内容滚动到最底部

参考原文:react scroll to bottom

通常,设置滚动高度可以通过设置元素的 scrollTop 属性,具体参见 Element.scrollTop - Web APIs | MDN (mozilla.org),使内容滚动到最底部可以将 scrollTop 设置成该元素的 scrollHeight 值。

1. 原生 HTML 中使用 JS 直接修改

在原生 HTML 中可以直接简单地获取到元素的 DOM 对象,以此直接修改元素的 scrollTop 属性。

<style>
  #scrollDiv {
    overflow: auto;
    height: 200px;
    width: 500px;
    border: 1px solid #999;
  }
</style>

<div id="example">
  <div id="scrollDiv"></div>
  <input type="button" value="插入一行" onclick="add()">
  <span class="notice">请点击“插入一行”按钮,插入最新信息,当出现滚动条时,滚动条将自动保持在底部。</span>
</div>

<script type="text/javascript">
  const $div = document.getElementById('scrollDiv');

  function add() {
    const now = new Date();
    $div.innerHTML = $div.innerHTML + 'time ' + now + '<br />';
    $div.scrollTop = $div.scrollHeight;
  }

  // 提前准备好足够撑满盒子的内容
  for (let i = 0; i < 20; ++i) {
    add();
  }
</script>

2. React 中使用 Ref 获取元素对象并修改

在 React 中,修改元素的样式并没有那么容易,因为原生元素的对象属性是只读的。所以可以使用 Ref 获取元素,然后使用 scrollIntoView 轻松设置。具体实现方法在如下代码段的注释里。

可以参阅:StackOverflow中相关问题

// As Tushar mentioned, you can keep a dummy div at the bottom of your chat:
// 可以预留一个空 div 在聊天消息的盒子底部
render () {
  return (
    <div>
      <div className="MessageContainer" >
        <div className="MessagesList">
          {this.renderMessages()}
        </div>
        <div style={{ float:"left", clear: "both" }}
             ref={(el) => { this.messagesEnd = el; }}>
        </div>
      </div>
    </div>
  );
}
// and then scroll to it whenever your component is updated (i.e. state updated as new messages are added):
// 在组件更新时,滚动到该空 div 的位置
scrollToBottom = () => {
  this.messagesEnd.scrollIntoView({ behavior: "auto" });
}

componentDidMount() {
  this.scrollToBottom();
}

componentDidUpdate() {
  this.scrollToBottom();
}

如果你觉得滚动过程有延迟或卡顿,可能是因为你的组件太大。每次状态改变都会出发组件更新,造成了性能问题。可以考虑拆分组件。

3. React Hooks 语法使用 useRef

函数组件使用 React Hooks 时,可以使用 useRef 的钩子函数获取到元素 ref 对象。参考官方文档 Hooks API Reference – React (reactjs.org)

export default function ChatHistories() {
  const messagesEnd = useRef<HTMLDivElement>(null);

  const scrollToBottom = () => {
    if (messagesEnd && messagesEnd.current) {
      messagesEnd.current.scrollIntoView({ behavior: 'smooth' });
    }
  };

  useEffect(() => {
    scrollToBottom();
  }, []);

  return (
    <div>
      <ul>{renderMessage()}</ul>
      <div style={{ clear: 'both', height: '1px', width: '100%' }} ref={messagesEnd}></div>
    </div>
  );
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容