我如何在ReactJS的onScroll事件中操纵DOM?

问题描述 投票:2回答:1

我正在尝试创建一个向上箭头按钮,如果我位于页面顶部,则将其设置为display: "none",并且当我进一步向下滚动时,我希望将其设置为显示:“阻止”。我怎样才能做到这一点?我正在尝试在handleScroll函数中操纵DOM,但是它不起作用。

我的T​​opButton.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;
javascript html reactjs dom
1个回答
1
投票

至少有两个原因不起作用:

  • 参见this question's answers;基本上,getElementsByClassName返回一个HTMLCollection,而不是单个元素,但是您注释掉的代码将其视为单个元素。

  • 如果您的组件曾经被重新渲染,它将以默认状态呈现,而不是通过DOM更改的更新状态。>

  • 但是这不是您使用React的方式。相反,您可以:

  1. 将按钮状态(是否应该被阻止)保留为组件中的状态;

  2. [渲染topbutton_button时使用该状态,并相应地设置其样式或类;和

  3. 更新handleScroll处理程序中的状态

  4. 另外一些注意事项:

  • [卸载组件时还需要删除处理程序

  • 您不应将箭头功能用于组件生命周期功能

  • 您不需要在箭头功能上使用bind(例如handleScroll)。 Either

  • 使其成为箭头函数or在构造函数中使用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;

我保留了handleScrollhandleClick的箭头功能。有一个使它们成为方法并在构造函数中使用bind的参数,但这主要是一种样式。 (好...样式,并且更容易模拟原型方法进行测试,这是使用原型方法和bind的非样式原因。)

© www.soinside.com 2019 - 2024. All rights reserved.