AI聊天机器人:新消息自动滚动与禁止空消息发送实现
解决AI聊天机器人的两个问题:自动滚动到底部和禁止空消息发送
一、实现收发消息时自动滚动到底部
之前添加h-full未生效,是因为缺少消息更新后的主动滚动触发逻辑。可以通过useRef获取消息容器节点,在消息列表更新时自动滚动到底部:
- 在App组件中创建DOM引用:
const messagesEndRef = useRef(null);
- 添加监听消息列表变化的副作用,每次更新后滚动到锚点位置:
useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
- 在消息列表末尾添加锚点元素:
<div className="w-full"> {messages.map((message, index) => ( <ChatMessage key={index} message={message.message} type={message.type} /> ))} <div ref={messagesEndRef} /> </div>
这样无论是发送消息还是收到机器人回复,页面都会自动跳转到最新消息位置。
二、禁止发送空消息
修改sendMessage函数,先判断输入内容(去除前后空格后)是否为空,为空则终止发送逻辑:
const sendMessage = ($event) => { // 区分键盘Enter触发和按钮点击触发,非Enter键直接返回 if($event.type === 'keydown' && $event.key !== "Enter") return; // 去除前后空格后判断是否为空 const trimmedMessage = input_message.trim(); if (!trimmedMessage) return; if (socket) { setMessages((prevMessages) => [ ...prevMessages, { type: "send", message: trimmedMessage, }, ]); socket.emit("message", trimmedMessage); setInputMessage(""); } };
修改后的完整代码
import { io } from "socket.io-client"; import { useState, useEffect, useRef } from "react"; function ChatMessage( {message, type}) { return( <div className={`flex w-full ${type == "send" ? "justify-end" : "justify-start"}`}> {type == "send" ? ( <div className="bg-green-300 p-2 m-3 rounded-b-xl rounded-tl-xl shadow-md" > {message} </div> ) : ( <div className="bg-gray-300 p-2 m-3 rounded-b-xl rounded-tr-xl shadow-md" > {message} </div> )} </div> ) } function App() { const [socket, setSocket] = useState(null); const [input_message, setInputMessage] = useState(""); const [messages, setMessages] = useState([]); const messagesEndRef = useRef(null); useEffect(() => { const newSocket = io("http://localhost:8080"); setSocket(newSocket); newSocket.on("response", (message) => { setMessages((prevMessages) => [ ...prevMessages, { type: "recieve", message, }, ]); }); return () => newSocket.close(); }, []); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); const sendMessage = ($event) => { if($event.type === 'keydown' && $event.key !== "Enter") return; const trimmedMessage = input_message.trim(); if (!trimmedMessage) return; if (socket) { setMessages((prevMessages) => [ ...prevMessages, { type: "send", message: trimmedMessage, }, ]); socket.emit("message", trimmedMessage); setInputMessage(""); } }; return ( <div className="p-5 h-screen bg-gradient-to-b from-green-950 to-green-200"> <div className="container mx-auto bg-blend-screen opacity-90 h-full flex flex-col"> <div className="flex-grow p-3 flex flex-col items-end overflow-auto"> <div className="w-full"> {messages.map((message, index) => ( <ChatMessage key={index} message={message.message} type={message.type} /> ))} <div ref={messagesEndRef} /> </div> </div> <div className="h-[100px] p-3 flex justify-center items-center bg-green-700 opacity-65"> <input onKeyDown={sendMessage} value={input_message} onChange={(e) => setInputMessage(e.target.value)} placeholder="Ask me anything...." type="text" className="w-full p-2 bg-transparent text-white border-white border-2 rounded-md outline-none" /> <button onClick={sendMessage} className="bg-white px-3 py-2 rounded-md mx-2 cursor-pointer"> Send </button> </div> </div> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Da'ad Al-Faleh
相关产品推荐
相关产品推荐

