乐闻世界logo
搜索文章和话题

React 如何在操作页面中滚动到底部?

6 个月前提问
3 个月前修改
浏览次数202

6个答案

1
2
3
4
5
6

在React中,如果您想要在某些情况下(例如,当内容更新时)将div滚动到底部,可以通过编程方式操作DOM来实现。以下是几种可以实现这个需求的方法:

使用ref和DOM方法

您可以通过React的ref属性获得DOM元素的直接引用,并使用原生的DOM方法来滚动到底部。这可以通过设置scrollTop来实现,scrollTop应该等于scrollHeight减去clientHeight

jsx
import React, { useRef, useEffect } from 'react'; function ChatComponent() { const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current.scrollIntoView({ behavior: "smooth" }); }; useEffect(scrollToBottom, []); // 如果希望在组件首次渲染时滚动到底部,可以添加空数组作为依赖项 return ( <div style={{ overflowY: 'auto', height: '500px' }}> {/* 消息内容 */} <div>{/* ... */}</div> {/* 用于滚动的元素 */} <div ref={messagesEndRef} /> </div> ); }

这里,useEffect用于在组件的生命周期内在适当的时刻触发滚动行为。

使用scrollTopscrollHeight

如果您想要更直接控制滚动位置,可以直接设置scrollTop属性:

jsx
import React, { useRef, useEffect } from 'react'; function ScrollToBottomComponent() { const divRef = useRef(null); const scrollToBottom = () => { const scrollHeight = divRef.current.scrollHeight; const height = divRef.current.clientHeight; const maxScrollTop = scrollHeight - height; divRef.current.scrollTop = maxScrollTop > 0 ? maxScrollTop : 0; }; useEffect(scrollToBottom, []); // 依据实际情况,可能需要添加其他依赖项,如消息数组 return ( <div ref={divRef} style={{ overflowY: 'auto', height: '500px' }}> {/* 消息内容 */} {/* ... */} </div> ); }

在这个例子中,我们在useEffect中调用scrollToBottom函数,这会在组件渲染后立即将div滚动到底部。

自动滚动处理新消息

如果您的div包含一个聊天界面,您可能希望在新消息到来时自动滚动到底部。这可以通过在useEffect中跟踪消息数组的变化来实现:

jsx
import React, { useRef, useEffect } from 'react'; function AutoScrollToBottomComponent({ messages }) { const divRef = useRef(null); useEffect(() => { if (divRef.current) { const { scrollHeight, clientHeight } = divRef.current; divRef.current.scrollTop = scrollHeight - clientHeight; } }, [messages]); // 当消息数组改变时触发滚动 return ( <div ref={divRef} style={{ overflowY: 'auto', height: '300px' }}> {messages.map((message, index) => ( <div key={index}>{message}</div> ))} </div> ); }

在这个例子中,每当传入组件的messages数组发生变化时,useEffect钩子就会执行,导致div自动滚动到底部。

以上就是在React中将div滚动到底部的几种方法。您可以根据您应用的具体需求选择适合的实现方式。

2024年6月29日 12:07 回复

As Tushar mentioned, you can keep a dummy div at the bottom of your chat:

shell
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):

shell
scrollToBottom = () => { this.messagesEnd.scrollIntoView({ behavior: "smooth" }); } componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); }

I'm using the standard Element.scrollIntoView method here.

2024年6月29日 12:07 回复

I just want to update the answer to match the new React.createRef() method, but it's basically the same, just have in mind the current property in the created ref:

shell
class Messages extends React.Component { const messagesEndRef = React.createRef() componentDidMount () { this.scrollToBottom() } componentDidUpdate () { this.scrollToBottom() } scrollToBottom = () => { this.messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) } render () { const { messages } = this.props return ( <div> {messages.map(message => <Message key={message.id} {...message} />)} <div ref={this.messagesEndRef} /> </div> ) } }

UPDATE:

Now that hooks are available, I'm updating the answer to add the use of the useRef and useEffect hooks, the real thing doing the magic (React refs and scrollIntoView DOM method) remains the same:

shell
import React, { useEffect, useRef } from 'react' const Messages = ({ messages }) => { const messagesEndRef = useRef(null) const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) } useEffect(() => { scrollToBottom() }, [messages]); return ( <div> {messages.map(message => <Message key={message.id} {...message} />)} <div ref={messagesEndRef} /> </div> ) }

Also made a (very basic) codesandbox if you wanna check the behaviour https://codesandbox.io/s/scrolltobottomexample-f90lz

2024年6月29日 12:07 回复

Do not use findDOMNode "because it blocks certain improvements in React in the future"

Class components with ref

shell
class MyComponent extends Component { componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); } scrollToBottom() { this.el.scrollIntoView({ behavior: 'smooth' }); } render() { return <div ref={el => { this.el = el; }} /> } }

Function components with hooks:

shell
import React, { useRef, useEffect } from 'react'; const MyComponent = () => { const divRef = useRef(null); useEffect(() => { divRef.current.scrollIntoView({ behavior: 'smooth' }); }); return <div ref={divRef} />; }
2024年6月29日 12:07 回复

Thanks to @enlitement

we should avoid using findDOMNode, we can use refs to keep track of the components

shell
render() { ... return ( <div> <div className="MessageList" ref={(div) => { this.messageList = div; }} > { messageListContent } </div> </div> ); } scrollToBottom() { const scrollHeight = this.messageList.scrollHeight; const height = this.messageList.clientHeight; const maxScrollTop = scrollHeight - height; this.messageList.scrollTop = maxScrollTop > 0 ? maxScrollTop : 0; } componentDidUpdate() { this.scrollToBottom(); }

reference:

2024年6月29日 12:07 回复

The easiest and best way I would recommend is.

My ReactJS version: 16.12.0


For Class Components

HTML structure inside render() function

shell
render() return( <body> <div ref="messageList"> <div>Message 1</div> <div>Message 2</div> <div>Message 3</div> </div> </body> ) )

scrollToBottom() function which will get reference of the element. and scroll according to scrollIntoView() function.

shell
scrollToBottom = () => { const { messageList } = this.refs; messageList.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"}); }

and call the above function inside componentDidMount() and componentDidUpdate()


For Functional Components (Hooks)

Import useRef() and useEffect()

shell
import { useEffect, useRef } from 'react'

Inside your export function, (same as calling a useState())

shell
const messageRef = useRef();

And let's assume you have to scroll when page load,

shell
useEffect(() => { if (messageRef.current) { messageRef.current.scrollIntoView( { behavior: 'smooth', block: 'end', inline: 'nearest' }) } })

OR if you want it to trigger once an action performed,

shell
useEffect(() => { if (messageRef.current) { messageRef.current.scrollIntoView( { behavior: 'smooth', block: 'end', inline: 'nearest' }) } }, [stateVariable])

And Finally, to your HTML structure

shell
return( <body> <div ref={messageRef}> // <= The only different is we are calling a variable here <div>Message 1</div> <div>Message 2</div> <div>Message 3</div> </div> </body> )

for more explanation about Element.scrollIntoView() visit developer.mozilla.org

More detailed explanation in Callback refs visit reactjs.org

2024年6月29日 12:07 回复

你的答案