javascript - 如何使 div 在反应中自动滚动(钩子)
问题描述
我目前正在制作一个聊天应用程序,并且在添加新的聊天消息时无法使 div 滚动到底部,我使用 css overflow-y:auto 使其能够滚动但无法弄清楚如何制作加载新聊天时,它总是滚动到底部。
这是我的 app.js 文件:
import "./App.css";
import React, { useEffect, useState ,useRef} from "react";
import io from 'socket.io-client';
let socket;
const CONNECTION_PORT = "localhost:3002/";
function App() {
//before login
const [logged, setLogged] = useState(false);
const [name,setName] = useState("");
const [room,setRoom] = useState("");
//after login
const [message,setMessage] = useState("");
const [messageList,setMessageList] = useState([]);
const ref = useRef();
useEffect(()=>{
socket = io(CONNECTION_PORT,{transports: ['websocket', 'polling', 'flashsocket']});
},[])
useEffect(()=>{
socket.on('recieve_message', (data)=>{
setMessageList([...messageList,data])
})
});
// useEffect(()=>{
// const objDiv = document.getElementById('scroll');
// objDiv.scrollTop = objDiv.scrollHeight;
// },[message])
function connectRoom(){
socket.emit('join', room)
setLogged(true);
}
function sendMessage(e){
let messageContent = {
room:room,
content:{
author:name,
message:message
}
}
socket.emit('send_message',messageContent)
setMessageList([...messageList,messageContent.content])
setMessage("");
}
return (
<div className="App">
{!logged?(
<div className="background">
<div className="box">
<span className="text-center">login</span>
<div className="input-container">
<input type="text" required="" onChange={e=> setName(e.target.value)}/>
<label>Full Name</label>
</div>
<div className="input-container">
<input type="text" required="" onChange={ e=> setRoom(e.target.value)}/>
<label>Room</label>
</div>
<button type="button" className="btn" onClick={connectRoom}>submit</button>
</div>
</div>
):(
<>
<div className="chatContainer">
<div className="messages" id="scroll">
{messageList.map((val,key)=>{
return (
<div className="messageContainer" id={val.author == name ? "You" : "Other"}>
<div className="messageIndividual">
{val.message}
</div>
<h1> {val.author}</h1>
</div>
);
})}
</div>
<div className="messageInputs">
<input type="text" placeholder="Type Here" onChange={ e=> setMessage(e.target.value)}/>
<button type="submit" onClick={sendMessage}> Send</button>
</div>
</div>
</>
)}
</div>
);
}
export default App;
这是我的css文件:
body{
margin: 0px;
padding: 0px;
}
.App{
margin: 0px;
padding: 0px;
display: grid;
place-items: center;
height: 100vh;
background-color: #2a2730;
}
.background{
margin: 0px;
padding: 0px;
width: 100%;
height: 100vh;
background-color: #e74c3c;
}
.text-center{
color:#fff;
text-transform:uppercase;
font-size: 23px;
margin: -50px 0 80px 0;
display: block;
text-align: center;
}
.box{
position:absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%);
background-color: rgba(0, 0, 0, 0.89);
border-radius:3px;
padding:70px 100px;
}
.input-container{
position:relative;
margin-bottom:25px;
}
.input-container label{
position:absolute;
top:0px;
left:0px;
font-size:16px;
color:#fff;
pointer-event:none;
transition: all 0.5s ease-in-out;
}
.input-container input{
border:0;
border-bottom:1px solid #555;
background:transparent;
width:100%;
padding:8px 0 5px 0;
font-size:16px;
color:#fff;
}
.input-container input:focus{
border:none;
outline:none;
border-bottom:1px solid #e74c3c;
}
.btn{
color:#fff;
background-color:#e74c3c;
outline: none;
border: 0;
color: #fff;
padding:10px 20px;
text-transform:uppercase;
margin-top:50px;
border-radius:2px;
cursor:pointer;
position:relative;
}
/*.btn:after{
content:"";
position:absolute;
background:rgba(0,0,0,0.50);
top:0;
right:0;
width:100%;
height:100%;
}*/
.input-container input:focus ~ label,
.input-container input:valid ~ label{
top:-12px;
font-size:12px;
}
.chatContainer {
width: 600px;
height: 350px;
border: 5px solid #0091ff;
border-radius: 10px;
display: flex;
flex-direction: column;
}
.chatContainer .messages {
flex: 80%;
width: 100%;
padding-left: 20px;
overflow-y: scroll;
/* flex-direction: column-reverse; */
}
.chatContainer .messageInputs {
flex: 20%;
width: 100%;
display: flex;
flex-direction: row;
}
.chatContainer .messageInputs input{
flex: 80%;
height: calc(100% -5px);
border: none;
border-top: 5px solid #0091ff;
padding-left: 20px;
font-size: 20px;
}
.chatContainer .messageInputs button{
flex: 20%;
height: 100%;
background-color: #0091ff;
border: none;
color: white;
font-size: 18px;
}
.messageContainer {
display: flex;
flex-direction: column;
width: calc(100% - 30px);
height: auto;
}
.messageContainer h1{
color: white;
font-family: Arial, Helvetica, sans-serif;
font-weight: 300;
font-size: 17px;
}
#You{
align-items: flex-end;
}
#Other {
align-items: flex-start;
}
#You .messageIndividual {
background-color: #5ff064;
color: black;
}
.messageIndividual {
width: 200px;
height: auto;
border-radius: 10px;
display: grid;
place-items: center;
background-color: #0091ff;
opacity: 0.9;
color: white;
font-family: Arial, Helvetica, sans-serif;
margin-right: 10px;
margin-top: 20px;
word-break: break-all;
white-space: pre-wrap;
padding: 4px;
}
解决方案
您可以添加一个带有参考波纹管消息列表的跨度,当收到新消息时将滚动到其中。
试试这个例子:
使用效果:
useEffect(() => {
scrollSpan.current.scrollIntoView({ behavior: "smooth" });
}, [messageList]);
使用参考:
const scrollSpan= useRef();
JSX:
<div className="messages" id="scroll">
{messageList.map((val,key)=>{
return (
<div className="messageContainer" id={val.author == name ?
"You" : "Other"}>
<div className="messageIndividual">
{val.message}
</div>
<h1> {val.author}</h1>
</div>
);
})}
<span ref={scrollSpan}></span>
</div>
推荐阅读
- html - 在多个 SVG 元素中管理相同的字体大小
- swift - Swift 5 - Facebook 登录:LoginManager() 回调不会在安装 Facebook 应用程序的情况下调用
- r - 如何在现有数据框中保存 H2O.GBM 的预测值?
- html - 如何在 div 元素 (HTML) 中居中图像
- c - 从字符串链表中删除一个字符串
- javascript - 为什么我不能用 JavaScript 函数覆盖这个 CSS?
- ios - 是什么让 UITableView 表现得像这样
- android - 使用数据绑定将数据从 viewModel 传递到 onClick 函数的正确方法是什么?
- excel - 代码不会确认奇数,不会将它们放在 B 列中
- bash - bash 中的陷阱执行顺序