我不知道为什么handleScroll只执行一次,而不是在我上下滚动时不执行一次。而且我需要以某种方式获取元素的高度,但我不确定除了documentElement之外的其他方式。该函数需要设置为true / false,以便我可以执行setState并在heroGallery div中添加/更改css动画的类。
import React, { Component } from "react";
class Intro extends Component {
constructor(props) {
super(props);
this.heroRef = React.createRef();
this.state = {};
}
componentDidMount = () => {
this.heroRef.current.getBoundingClientRect();
let hero2 = this.heroRef;
console.log(this.heroRef.current);
window.addEventListener("scroll", this.handleScroll(hero2));
};
componentWillUnmount = () => {
window.removeEventListener("scroll", this.handleScroll);
};
handleScroll = elm => {
var rect = elm.current.getBoundingClientRect();
//var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
//return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
};
render() {
return (
<div className="introCont">
<div className="introFirstSection" />
<div className="heroSection">
<div className="heroGallery" ref={this.heroRef}>
<div className="slide-down">item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
</div>
</div>
</div>
);
}
}
export default Intro;
编辑: 从Switch中取出我的简介组件可以使其正常工作。
import React, { lazy, Suspense, Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { connect } from "react-redux";
import * as actions from "./actions";
//import asyncComponent from "./components/AsyncComponent";
//const Header = asyncComponent(() => import("./Header"));
import Intro from "./components/Intro";
const Header = lazy(() => import("./components/Header"));
const Footer = lazy(() => import("./components/Footer"));
const Landing = lazy(() => import("./components/Landing"));
const Profile = lazy(() => import("./components/Profile"));
const BookList = lazy(() => import("./components/books/BookList"));
const BookNote = lazy(() => import("./components/books/BookNote"));
const StatsChart = lazy(() => import("./components/StatsChart"));
class App extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
return (
<BrowserRouter>
<div className="rootdk">
<Suspense fallback={<div />}>
<Header />
</Suspense>
<div className="container">
<Suspense fallback={<div className="loader" />}>
<Switch>
<Route exact path="/intro" component={() => <Intro />} />
<Route
exact
path="/mybooks"
component={() =>
this.props.thisuser ? <BookList /> : <Landing />
}
/>
<Route
exact
path="/booknotes"
component={() =>
this.props.thisuser ? <BookNote /> : <Landing />
}
/>
<Route
exact
path="/statschart"
component={() =>
this.props.thisuser ? <StatsChart /> : <Landing />
}
/>
<Route
exact
path="/profile"
component={() =>
this.props.thisuser ? <Profile /> : <Landing />
}
/>
<Route exact path="/" component={Landing} />
</Switch>
</Suspense>
<Suspense fallback={<div />}>
<Footer />
</Suspense>
</div>
</div>
</BrowserRouter>
);
}
}
function mapStateToProps(props) {
return { thisuser: props.auth };
}
export default connect(
mapStateToProps,
actions
)(App);
答案 0 :(得分:2)
这是因为您正在调用addEventListener
中的方法。
演示:https://codesandbox.io/s/nv16oq6j?fontsize=14
将您的componentDidMount
函数更改为此。
componentDidMount = () => {
this.heroRef.current.getBoundingClientRect();
let hero2 = this.heroRef;
console.log(this.heroRef.current);
window.addEventListener("scroll", () => this.handleScroll(hero2));
};
我所做的只是将addEventListener
的第二个参数作为函数。
答案 1 :(得分:0)
另一个答案是使用HTML5 API,这使它变得容易得多: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
此外,容器显然必须具有固定的高度,并且将溢出属性设置为自动或滚动。
示例:
import React, { Component } from "react";
import ReactDOM from "react-dom";
class Intro extends Component {
constructor(props) {
super(props);
this.heroRef = React.createRef();
this.state = {
heroanim: "no"
};
}
componentDidMount = () => {
setTimeout(() => {
this.startup();
}, 500);
this.startup();
};
componentWillUnmount = () => {};
startup = () => {
//the class we want to observe for visibility changes, scrolling for animation.
let adBox = document.querySelector(".heroSection");
//checks if page was tabbed out or hidden. separate from intersectionobserver
document.addEventListener(
"visibilitychange",
this.handleVisibilityChange,
false
);
//intersectionobserveroptions. root is highest element you want to compare to. threshhold is % visibility of element you're comparing to root. 'callback activated when 50% visibility.'
let observerOptions = {
root: null,
rootMargin: "0px",
threshold: [0.7]
};
//create new intersection observer
let adObserver = new IntersectionObserver(
this.intersectionCallback,
observerOptions
);
//call it.
adObserver.observe(adBox);
};
handleVisibilityChange = () => {
if (document.hidden) {
//changeclass to no animate through setstate
} else {
//changeclass to animate
}
};
intersectionCallback = entries => {
entries.forEach(entry => {
let adBox = entry.target;
if (entry.isIntersecting) {
this.setState({ heroanim: "yes" });
} else {
console.log("not");
this.setState({ heroanim: "no" });
}
});
};
render() {
return (
<div className="introCont">
<div className="introFirstSection" />
<div
className={
this.state.heroanim === "yes"
? "heroSection heroAnim"
: "heroSection"
}
ref={this.heroRef}
>
<div className="heroGallery">
<div className="slide-down">item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
</div>
</div>
</div>
);
}
}
export default Intro;