我想建立一个聊天系统,并自动滚动到底部时,进入窗口,当新的消息进来。如何在React中自动滚动到容器底部?


当前回答

谢谢你的回答,但我认为我们可以做得更好, 对于滚动到底部,我们应该使用这个:

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

但如果你想滚动顶部,你应该使用这个:

scrollToTop = () => {
   this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" });
}   

这些代码很常见:

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>
  );
}

其他回答

在上面的答案中,scrollIntoView(…)方法有两个主要问题:

it's semantically incorrect, as it causes the entire page to scroll if your parent element is scrolled outside the window boundaries. The browser literally scrolls anything it needs to in getting the element visible. in a functional component using useEffect(), you get unreliable results, at least in Chrome 96.0.4665.45. useEffect() gets called too soon on page reload and the scroll doesn't happen. Delaying scrollIntoView with setTimeout(..., 0) fixes it for page reload, but not first load in a fresh tab, at least for me. shrugs

这是我一直在使用的解决方案,它很可靠,而且更兼容旧的浏览器:

function Chat() {
   const chatParent = useRef<HTMLDivElement(null);

   useEffect(() => {
      const domNode = chatParent.current;
      if (domNode) {
         domNode.scrollTop = domNode.scrollHeight;
      }
   })
   return (
      <div ref={chatParent}>
         ...
      </div>
   )
}

工作的例子:

您可以使用DOM scrollIntoView方法使组件在视图中可见。

为此,在呈现组件时,只需使用ref属性为DOM元素提供一个引用ID。然后在componentDidMount生命周期上使用scrollIntoView方法。我只是把这个解决方案的工作示例代码。以下是每次接收到消息时的组件呈现。您应该编写代码/方法来呈现该组件。

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是作为道具传递的特定聊天消息的唯一ID

Reference your messages container. <div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div> Find your messages container and make its scrollTop attribute equal scrollHeight: scrollToBottom = () => { const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer); messagesContainer.scrollTop = messagesContainer.scrollHeight; }; Evoke above method on componentDidMount and 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>
        );
    }
}

如果用户已经在可滚动部分的底部,react- scrolable -feed会自动向下滚动到最新的元素。否则,它将使用户处于相同的位置。我认为这对聊天组件非常有用:)

我认为这里的其他答案将强制每次滚动,无论滚动条在哪里。scrollIntoView的另一个问题是,如果您的可滚动div不在视图中,它将滚动整个页面。

它可以这样使用:

import * as React from 'react'

import ScrollableFeed from 'react-scrollable-feed'

class App extends React.Component {
  render() {
    const messages = ['Item 1', 'Item 2'];

    return (
      <ScrollableFeed>
        {messages.map((message, i) => <div key={i}>{message}</div>)}
      </ScrollableFeed>
    );
  }
}

只要确保包装器组件具有特定的高度或max-height即可

免责声明:我是包裹的所有者

这对我很有用

messagesEndRef.current.scrollTop = messagesEndRef.current.scrollHeight

const messagesEndRef = useRef();使用