使用 React 发送消息时聊天滚动到底部

Chat scroll to bottom when send a message using React

我希望聊天 window 在我发送文本时向下滚动。

实际上发送的消息不会触发滚动,所以它们被隐藏了。

这是一个 example ( I'm using the chat component of MS Fluent UI for React library )

我找到了这个 但我无法集成它(不知道在哪里声明了 endMessage )在我的例子中它的值是 undefined.

import React from "react";
import { Avatar, Chat, Divider, Input } from "@fluentui/react-northstar";
import { AcceptIcon } from "@fluentui/react-icons-northstar";

const janeAvatar = {
  image: "public/images/avatar/small/ade.jpg",
  status: {
    color: "green",
    icon: <AcceptIcon />
  }
};

const ChatExample = () => {
  const items = [
    {
      message: (
        <Chat.Message
          content="Hello"
          author="John Doe"
          timestamp="Yesterday, 10:15 PM"
          mine
        />
      ),
      contentPosition: "end",
      attached: "top",
      key: "message-id-1"
    },
    {
      message: (
        <Chat.Message
          content="I'm back!"
          author="John Doe"
          timestamp="Yesterday, 10:15 PM"
          mine
        />
      ),
      contentPosition: "end",
      attached: true,
      key: "message-id-2"
    },
    {
      message: (
        <Chat.Message
          content={{
            content: (
              <div>
                What do you think about <a href="#">www.goodFood.com</a>?
              </div>
            )
          }}
          author="John Doe"
          timestamp="Yesterday, 10:15 PM"
          mine
        />
      ),
      contentPosition: "end",
      attached: "bottom",
      key: "message-id-3"
    },
    {
      gutter: <Avatar {...janeAvatar} />,
      message: (
        <Chat.Message
          content="Hi"
          author="Jane Doe"
          timestamp="Yesterday, 10:15 PM"
        />
      ),
      attached: "top",
      key: "message-id-4"
    },
    {
      gutter: <Avatar {...janeAvatar} />,
      message: (
        <Chat.Message
          content="Looks good!"
          author="Jane Doe"
          timestamp="Yesterday, 10:15 PM"
        />
      ),
      attached: true,
      key: "message-id-5"
    },
    {
      gutter: <Avatar {...janeAvatar} />,
      message: (
        <Chat.Message
          content={
            <div>
              I also like <a href="#">www.goodFood2.com</a>.
            </div>
          }
          author="Jane Doe"
          timestamp="Yesterday, 10:15 PM"
        />
      ),
      attached: "bottom",
      key: "message-id-6"
    },
    {
      message: (
        <Chat.Message
          content="Would you like to grab lunch there?"
          author="John Doe"
          timestamp="Yesterday, 10:16 PM"
          mine
        />
      ),
      contentPosition: "end",
      key: "message-id-7"
    },
    {
      gutter: <Avatar {...janeAvatar} />,
      message: (
        <Chat.Message
          content="Sure! Let's try it."
          author="Jane Doe"
          timestamp="Yesterday, 10:15 PM"
        />
      ),
      key: "message-id-8"
    },
    {
      children: <Divider content="Today" color="brand" important />,
      key: "message-id-9"
    },
    {
      message: (
        <Chat.Message
          content="Ok, let's go."
          author="John Doe"
          timestamp="Today, 11:15 PM"
          mine
        />
      ),
      contentPosition: "end",
      key: "message-id-10"
    }
  ];
  const [inputValue, setInputValue] = React.useState("");
  const [itemsChat, setItemsChat] = React.useState(items);
  const chatStyle = {
    height: 500,
    overflow: "scroll"
  };
  const handleKeyDown = event => {
    if (event.key == "Enter") {
      console.log(event);
      let elm = {
        message: (
          <Chat.Message
            content={inputValue}
            author="John Doe"
            timestamp="Yesterday, 10:15 PM"
            mine
          />
        ),
        contentPosition: "end",
        attached: "top",
        key: "message-id-1"
      };
      setItemsChat(itemsChat => [...itemsChat, elm]);
      setInputValue("");
    }
  };
  return (
    <div>
      <Chat style={chatStyle} items={itemsChat} />

      <Input
        fluid
        placeholder="Inverted color input..."
        value={inputValue}
        onKeyDown={event => handleKeyDown(event)}
        onChange={event => setInputValue(event.target.value)}
      />
    </div>
  );
};

export default ChatExample;

endMessage 变量是对他们在聊天结束时包含的空 div 的引用。

您可以在 React 文档中了解有关 React 中 refs 的更多信息:https://reactjs.org/docs/refs-and-the-dom.html

另一个问题的示例代码的不同之处在于它们不使用内置的 createRef 方法,而是传递一个自定义函数,该函数将更新 .endMessage 变量以指向当前元素。

React 文档中显示的方法是在组件的顶部添加一个变量,并用 useRef 挂钩填充它(将其命名为 endMessage 以与另一个 post 的方案保持一致) 然后在 div 中作为最后一条聊天消息,您可以将该变量用于 ref 属性:

<div ref={endMessage} />

在成功新建 post 的回调函数中,您将调用 endMessage.current.scrollIntoView(注意:使用内置的 React ref 钩子或函数时,必须使用 current。如果您通过ref 道具的自定义函数,您始终可以直接分配引用的当前部分,如其他 SO post.

所示

我不熟悉您正在使用的聊天组件,因此我无法就如何将 div 放在最底部提供任何提示。另一个问题是关于 generic/self-programmed 聊天工具,假设您可以控制聊天框,并可以在呈现动态聊天消息列表的末尾放置一个静态元素。

您可以简单地使用带有 itemsChat 的效果作为依赖。只需抓住聊天 ul 元素并滚动到底部。

useEffect(() => {
    document.querySelector('.ui-chat').scrollTop = document.querySelector('.ui-chat').scrollHeight
  }, [itemsChat])

Working copy of your code is here