背景:js实现滚动条一直在底部靠的是元素的scrollTop和scrollHeight来实现的,可是在React中有些行不通。
原理:在容器的底部添加一个空的div,使该div一直处于浏览器视口内,这样就可以让容器的滚动条位于底部。
知识点:
useState: 通过在函数组件里调用它来给组件添加一些内部 state, useState 唯一的参数就是初始 state
useEffect:给函数组件增加了操作副作用的能力,它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
useRef:返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
Element.scrollIntoView() :让当前的元素滚动到浏览器窗口的可视区域内。
方案一:用hooks实现
import React, {useState, useEffect, useRef, PureComponent} from "react";
import ReactDOM from "react-dom";
import uuid from "uuid";
function Scroll() {
const [messages, setMessages] = useState([]);
const addMessages = () => {
setMessages(m => [...m, uuid()]);
};
const messagesEndRef = useRef(null);
const scrollToBottom = () => {
console.log(messagesEndRef.current)
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
};
useEffect(scrollToBottom, [messages]);
return (
<div className="App">
<button className="addButton" onClick={addMessages}>
Add message
</button>
<div style={{display:"flex", flexDirection:"column", height:"100px", overflow:"scroll", marginTop:"30px", border:"1px solid #000"}}>
{messages.map(message => (
<span key={message}>{message}</span>
))}
<div ref={messagesEndRef} />
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Scroll />, rootElement);
方案二:用类组件实现
import React, {useState, useEffect, useRef, PureComponent} from "react";
import uuid from "uuid";
class Scroll extends PureComponent {
state= {
messages: [],
flag: false
};
componentDidUpdate(prevProps, prevState, snapshot) {
const { message } = this.state;
this.scrollToBottom();
}
scrollToBottom = () => {
const messagesEndRef = document.getElementById("messagesEndRef");
messagesEndRef.scrollIntoView({ behavior: "smooth" });
};
addMessages = () => {
const { messages, flag } = this.state;
// console.log(uuid());
messages.push(uuid());
this.setState({
messages,
flag:!flag
})
};
render() {
const { messages } = this.state;
return (
<div className="App">
<button className="addButton" onClick={this.addMessages}>
Add message
</button>
<div style={{display:"flex", flexDirection:"column", height:"100px", overflow:"scroll", marginTop:"30px", border:"1px solid #000"}}>
{messages.map(message => (
<span key={message}>{message}</span>
))}
<div id="messagesEndRef" />
</div>
</div>
)
}
}
export default Scroll
个人推荐第一种方案,第二种方案可行但是操作DOM性能一般。
网友评论