我想构建一个聊天系统,并在进入窗口和收到新消息时自动滚动到底部。如何在React中自动滚动到容器的底部?
如何在反应中滚动到底部?
I like doing it the following way.
componentDidUpdate(prevProps, prevState){
this.scrollToBottom();
}
scrollToBottom() {
const {thing} = this.refs;
thing.scrollTop = thing.scrollHeight - thing.clientHeight;
}
render(){
return(
<div ref={`thing`}>
<ManyThings things={}>
</div>
)
}
As another option it is worth looking at react scroll component.
谢谢“ metakermit”的好答案,但是我认为我们可以做得更好一些,滚动到底部,我们应该使用以下代码:
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
}
but if you want to scroll top, you should use this:
scrollToTop = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" });
}
and this codes are common:
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
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>
);
}
工作示例:
您可以使用DOM scrollIntoView方法使组件在视图中可见。
为此,在渲染组件时,只需使用ref属性为DOM元素提供参考ID 。然后使用方法scrollIntoView上componentDidMount的生命周期。我只是在为该解决方案提供一个有效的示例代码。以下是每次接收到消息时都会呈现的组件。您应该编写用于渲染此组件的代码/方法。
class ChatMessage extends Component {
scrollToBottom = (ref) => {
this.refs[ref].scrollIntoView({ behavior: "smooth" });
}
componentDidMount() {
this.scrollToBottom(this.props.message.MessageId);
}
render() {
return(
<div ref={this.props.message.MessageId}>
<div>Message content here...</div>
</div>
);
}
}
这this.props.message.MessageId是作为传递的特定聊天消息的唯一IDprops
我在消息末尾创建了一个空元素,然后滚动到该元素。无需跟踪引用。
引用您的消息容器。
<div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>找到您的消息容器并将其
scrollTop属性设为相等scrollHeight:scrollToBottom = () => { const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer); messagesContainer.scrollTop = messagesContainer.scrollHeight; };在
componentDidMount和上调用上述方法componentDidUpdate。componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); }
这就是我在代码中使用它的方式:
export default class StoryView extends Component {
constructor(props) {
super(props);
this.scrollToBottom = this.scrollToBottom.bind(this);
}
scrollToBottom = () => {
const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
};
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
render() {
return (
<div>
<Grid className="storyView">
<Row>
<div className="codeView">
<Col md={8} mdOffset={2}>
<div ref={(el) => { this.messagesContainer = el; }}
className="chat">
{
this.props.messages.map(function (message, i) {
return (
<div key={i}>
<div className="bubble" >
{message.body}
</div>
</div>
);
}, this)
}
</div>
</Col>
</div>
</Row>
</Grid>
</div>
);
}
}
感谢@enlitement
我们应该避免使用findDOMNode,我们可以refs用来跟踪组件
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();
}
参考:
正如Tushar所提到的,您可以在聊天的底部保留一个虚拟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>
);
}
然后在组件更新时滚动到它(即,随着添加新消息而更新状态):
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth" });
}
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
我在这里使用标准的Element.scrollIntoView方法。
The easiest and best way I would recommend is.
My ReactJS version: 16.12.0
HTML structure inside
render()functionscrollToBottom()function which will get reference of the element. and scroll according toscrollIntoView()function.and call the above function inside
componentDidMount()andcomponentDidUpdate()for more explanation about
Element.scrollIntoView()visit developer.mozilla.org