我正在尝试创建一个向上箭头按钮,如果我位于页面顶部,则将其设置为display: "none"
,并且当我进一步向下滚动时,我希望将其设置为显示:“阻止”。我怎样才能做到这一点?我正在尝试在handleScroll函数中操纵DOM,但是它不起作用。
我的TopButton.js组件
import React from "react";
import "../assets/arrow-up.png";
class TopButton extends React.Component {
constructor(props) {
super(props);
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount = () => {
window.addEventListener("scroll", this.handleScroll, true);
};
handleClick = () => {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
};
handleScroll = () => {
console.log("scroll");
let x = document.getElementsByClassName("topbutton_button");
var x = document.getElementsByClassName("topbutton_button");
// x.style.display = "none";
// console.log(event.target.className);
// if (
// document.body.scrollTop > 40 ||
// document.documentElement.scrollTop > 40
// ) {
// style.display = "block";
// } else {
// display = "none";
// }
};
render() {
return (
<div className="topbutton_container">
<button
style={{ display: "block" }}
onClick={this.handleClick}
onScroll={this.handleScroll}
className="topbutton_button"
>
<img src={require("../assets/arrow-up.png")} />
</button>
</div>
);
}
}
export default TopButton;
至少有两个原因不起作用:
参见this question's answers;基本上,getElementsByClassName
返回一个HTMLCollection
,而不是单个元素,但是您注释掉的代码将其视为单个元素。
如果您的组件曾经被重新渲染,它将以默认状态呈现,而不是通过DOM更改的更新状态。>
但是这不是您使用React的方式。相反,您可以:
将按钮状态(是否应该被阻止)保留为组件中的状态;
[渲染topbutton_button
时使用该状态,并相应地设置其样式或类;和
更新handleScroll
处理程序中的状态
另外一些注意事项:
[卸载组件时还需要删除处理程序
您不应将箭头功能用于组件生命周期功能
您不需要在箭头功能上使用bind
(例如handleScroll
)。 Either
bind
进行绑定。遵循这些思路,请参见***
注释
import React from "react"; import "../assets/arrow-up.png"; // *** Reusable function to decide whether we're "at the top" or not function bodyIsAtTop() { return ( document.body.scrollTop <= 40 && document.documentElement.scrollTop <= 40 ); } class TopButton extends React.Component { constructor(props) { super(props); // *** Initial state this.state = { atTop: bodyIsAtTop() }; // *** No need for the following if you use an arrow function // this.handleScroll = this.handleScroll.bind(this); } // *** Don't make this an arrow, make it a method componentDidMount() { window.addEventListener("scroll", this.handleScroll, true); }; // *** Need to unbind when unmounted componentWillUnmount = () => { window.removeEventListener("scroll", this.handleScroll, true); }; handleClick = () => { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; }; handleScroll = () => { // *** Update state (possibly; if the flag isn't different, this doesn't do anything) this.setState({atTop: bodyIsAtTop()}); }; render() { // *** Get the flag from state, use it below in style const {atTop} = this.state; return ( <div className="topbutton_container"> <button style={{ display: atTop ? "none" : "block" }} onClick={this.handleClick} onScroll={this.handleScroll} className="topbutton_button" > <img src={require("../assets/arrow-up.png")} /> </button> </div> ); } } export default TopButton;
我保留了
handleScroll
和handleClick
的箭头功能。有一个使它们成为方法并在构造函数中使用bind
的参数,但这主要是一种样式。 (好...样式,并且更容易模拟原型方法进行测试,这是使用原型方法和bind
的非样式原因。)