我使用bootstrap 4导航栏,想要在ig 400px向下滚动后更改背景颜色。我正在查看反应文档,发现了一个onScroll,但无法找到相关信息。到目前为止我已经
了我不知道我是否正在使用正确的事件监听器或如何设置身高等。
我并没有真正设置内联样式
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = { scrollBackground: 'nav-bg' };
this.handleScroll = this.handleScroll.bind(this);
}
handleScroll(){
this.setState ({
scrollBackground: !this.state.scrollBackground
})
}
render() {
const scrollBg = this.scrollBackground ? 'nav-bg scrolling' : 'nav-bg';
return (
<div>
<Navbar inverse toggleable className={this.state.scrollBackground}
onScroll={this.handleScroll}>
...
</Navbar>
</div>
);
}
}
export default App;
答案 0 :(得分:9)
添加滚动侦听器的一种方法是使用componentDidMount()
生命周期方法。以下示例应该给你一个想法:
import React from 'react';
import { render } from 'react-dom';
class App extends React.Component {
state = {
isTop: true,
};
componentDidMount() {
document.addEventListener('scroll', () => {
const isTop = window.scrollY < 100;
if (isTop !== this.state.isTop) {
this.setState({ isTop })
}
});
}
render() {
return (
<div style={{ height: '200vh' }}>
<h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
</div>
);
}
}
render(<App />, document.getElementById('root'));
当您的“滚动”位置为100及以上时,这会将文本从“向下滚动”更改为“向上滚动”。
编辑:应该避免在每个滚动上更新状态的过度杀伤。仅在布尔值更改时更新它。
答案 1 :(得分:4)
const [scroll, setScroll] = useState(false);
useEffect(() => {
window.addEventListener("scroll", () => {
setScroll(window.scrollY > specify_height_you_want_to_change_after_here);
});
}, []);
然后您可以根据滚动条更改班级或其他任何内容。
<nav className={scroll ? "bg-black" : "bg-white"}>...</nav>
答案 2 :(得分:2)
这是更好的
import React from 'react';
import { render } from 'react-dom';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isTop: true
};
this.onScroll = this.onScroll.bind(this);
}
componentDidMount() {
document.addEventListener('scroll', () => {
const isTop = window.scrollY < 100;
if (isTop !== this.state.isTop) {
this.onScroll(isTop);
}
});
}
onScroll(isTop) {
this.setState({ isTop });
}
render() {
return (
<div style={{ height: '200vh' }}>
<h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
</div>
);
}
}
render(<App />, document.getElementById('root'));
答案 3 :(得分:2)
对于那些在2019年阅读此问题的人,我采取了@glennreyes的答案,并使用了 React Hooks :
const [scroll, setScroll] = useState(0)
useEffect(() => {
document.addEventListener("scroll", () => {
const scrollCheck = window.scrollY < 100
if (scrollCheck !== scroll) {
setScroll(scrollCheck)
}
})
})
请记住, useState 具有两个元素的数组,首先是状态对象,其次是对其进行更新的功能。
基本上, useEffect 帮助我们替换了 componentDidmount ,当前编写的函数不会进行任何清理,因为在这种情况下是不必要的。
如果您发现有必要进行清理,则只需在 useEffect 内部返回一个函数。
您可以全面阅读here。
答案 4 :(得分:0)
我已将@PouyaAtaei的用例答案做了些修改。
import { useState, useEffect } from "react"
// Added distance parameter to determine how much
// from the top tell return value is updated.
// The name of the hook better reflects intended use.
export const useHasScrolled = (distance = 10) => {
// setting initial value to false
const [scroll, setScroll] = useState(false)
// running on mount
useEffect(() => {
const onScroll = () => {
// Logic is false tell user reaches threshold, then true after.
const scrollCheck = window.scrollY >= distance;
if (scrollCheck !== scroll) {
setScroll(scrollCheck)
}
}
// setting the event handler from web API
document.addEventListener("scroll", onScroll)
// cleaning up from the web API
return () => {
document.removeEventListener("scroll", onScroll)
}
}, [scroll, setScroll])
return scroll
}
};
呼叫钩子:
Const component = () => {
// calling our custom hook and optional distance agument.
const scroll = useHasScrolled(250)
}
答案 5 :(得分:0)
这是/我对滚动显示和隐藏随机页面元素的挂钩方法的另一种看法。
我受到了Dan Abramov's post here的启发。
您可以在此CodeSandbox demo中查看完整的工作示例。
import React, { useState, useEffect } from "react";
export const useScroll = callback => {
const [scrollDirection, setScrollDirection] = useState(true);
const handleScroll = () => {
const direction = (() => {
// if scroll is at top or at bottom return null,
// so that it would be possible to catch and enforce a special behaviour in such a case.
if (
window.pageYOffset === 0 ||
window.innerHeight + Math.ceil(window.pageYOffset) >=
document.body.offsetHeight
)
return null;
// otherwise return the direction of the scroll
return scrollDirection < window.pageYOffset ? "down" : "up";
})();
callback(direction);
setScrollDirection(window.pageYOffset);
};
// adding and cleanning up de event listener
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
});
};
useScroll(direction => {
setScrollDirection(direction);
});
import React, { useState } from "react";
import ReactDOM from "react-dom";
import CustomElement, { useScroll } from "./element";
import Scrollable from "./scrollable";
function Page() {
const [scrollDirection, setScrollDirection] = useState(null);
useScroll(direction => {
setScrollDirection(direction);
});
return (
<div>
{/* a custom element that implements some scroll direction behaviour */}
{/* "./element" exports useScroll hook and <CustomElement> */}
<CustomElement scrollDirection={scrollDirection} />
{/* just a lorem ipsum long text */}
<Scrollable />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Page />, rootElement);
import React, { useState, useEffect } from "react";
export default props => {
const [elementVisible, setElementVisible] = useState(true);
const { scrollDirection } = props;
// when scroll direction changes element visibility adapts, but can do anything we want it to do
// U can use ScrollDirection and implement some page shake effect while scrolling
useEffect(() => {
setElementVisible(
scrollDirection === "down"
? false
: scrollDirection === "up"
? true
: true
);
}, [scrollDirection]);
return (
<div
style={{
background: "#ff0",
padding: "20px",
position: "fixed",
width: "100%",
display: `${elementVisible ? "inherit" : "none"}`
}}
>
element
</div>
);
};
答案 6 :(得分:0)
这是两个钩子-一个用于方向(上/下/无),另一个用于实际位置
像这样使用:
useScrollPosition(position => {
console.log(position)
})
useScrollDirection(direction => {
console.log(direction)
})
这是钩子:
import { useState, useEffect } from "react"
export const SCROLL_DIRECTION_DOWN = "SCROLL_DIRECTION_DOWN"
export const SCROLL_DIRECTION_UP = "SCROLL_DIRECTION_UP"
export const SCROLL_DIRECTION_NONE = "SCROLL_DIRECTION_NONE"
export const useScrollDirection = callback => {
const [lastYPosition, setLastYPosition] = useState(window.pageYOffset)
const [timer, setTimer] = useState(null)
const handleScroll = () => {
if (timer !== null) {
clearTimeout(timer)
}
setTimer(
setTimeout(function () {
callback(SCROLL_DIRECTION_NONE)
}, 150)
)
if (window.pageYOffset === lastYPosition) return SCROLL_DIRECTION_NONE
const direction = (() => {
return lastYPosition < window.pageYOffset
? SCROLL_DIRECTION_DOWN
: SCROLL_DIRECTION_UP
})()
callback(direction)
setLastYPosition(window.pageYOffset)
}
useEffect(() => {
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
})
}
export const useScrollPosition = callback => {
const handleScroll = () => {
callback(window.pageYOffset)
}
useEffect(() => {
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
})
}
答案 7 :(得分:0)
如何修复:
警告:无法对已卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请取消 useEffect 清理函数中的所有订阅和异步任务。 菜单新闻
const [scroll, setScroll] = useState(false);
useEffect(() => {
window.addEventListener("scroll", () => {
setScroll(window.scrollY > specify_height_you_want_to_change_after_here);
});
}, []);
答案 8 :(得分:0)
没有滚动事件监听器的方法
import { useEffect, useState } from "react";
interface Props {
elementId: string;
position: string;
}
const useCheckScrollPosition = ({ elementId, position }: Props) => {
const [isOverScrollPosition, setIsOverScrollPosition] = useState<boolean>(false);
useEffect(() => {
if (
"IntersectionObserver" in window &&
"IntersectionObserverEntry" in window &&
"intersectionRatio" in window.IntersectionObserverEntry.prototype
) {
const observer = new IntersectionObserver((entries) => {
setIsOverScrollPosition(entries[0].boundingClientRect.y < 0);
});
const flagElement = document.createElement("div");
flagElement.id = elementId;
flagElement.className = "scroll-flag";
flagElement.style.top = position;
const container = document.getElementById("__next"); // React div id
const oldFlagElement = document.getElementById(elementId);
if (!oldFlagElement) container?.appendChild(flagElement);
const elementToObserve = oldFlagElement || flagElement;
observer.observe(elementToObserve);
}
}, [elementId, position]);
return isOverScrollPosition;
};
export default useCheckScrollPosition;
然后你可以像这样使用它:
const isOverScrollPosition = useCheckScrollPosition({
elementId: "sticky-header",
position: "10px",
});
isOverScrollPosition
是一个布尔值,如果您滚动到位置提供的值 (10 像素),则为 true,如果滚动到其下方,则为 false。
这种方法会在 react root 中添加一个标志 div。