Ale*_*rez 111 javascript reactjs
我在React中构建了一个组件,它应该在窗口滚动上更新自己的样式以创建视差效果.
组件render
方法如下所示:
function() {
let style = { transform: 'translateY(0px)' };
window.addEventListener('scroll', (event) => {
let scrollTop = event.srcElement.body.scrollTop,
itemTranslate = Math.min(0, scrollTop/3 - 60);
style.transform = 'translateY(' + itemTranslate + 'px)');
});
return (
<div style={style}></div>
);
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为React不知道组件已更改,因此组件不会被重新呈现.
我已经尝试将值存储在itemTranslate
组件的状态中,并调用setState
滚动回调.但是,这使得滚动无法使用,因为这非常慢.
有关如何做到这一点的任何建议?
谢谢.
Aus*_*eco 206
你应该绑定监听器componentDidMount
,这样它只创建一次.您应该能够将样式存储在状态中,监听器可能是性能问题的原因.
像这样的东西:
componentDidMount: function() {
window.addEventListener('scroll', this.handleScroll);
},
componentWillUnmount: function() {
window.removeEventListener('scroll', this.handleScroll);
},
handleScroll: function(event) {
let scrollTop = event.srcElement.body.scrollTop,
itemTranslate = Math.min(0, scrollTop/3 - 60);
this.setState({
transform: itemTranslate
});
},
Run Code Online (Sandbox Code Playgroud)
小智 37
带钩子
import React, { useEffect, useState } from 'react';
function MyApp () {
const [offset, setOffset] = useState(0);
useEffect(() => {
window.onscroll = () => {
setOffset(window.pageYOffset)
}
}, []);
console.log(offset);
};
Run Code Online (Sandbox Code Playgroud)
Con*_*kos 25
您可以将函数传递给onScroll
React元素上的事件:https://facebook.github.io/react/docs/events.html#ui-events
<ScrollableComponent
onScroll={this.handleScroll}
/>
Run Code Online (Sandbox Code Playgroud)
另一个类似的答案:https://stackoverflow.com/a/36207913/1255973
adr*_*mer 17
帮助那些在使用Austins答案时注意到滞后行为/性能问题的人,并想要一个使用评论中提到的参考的示例,这是我用来切换类的滚动向上/向下图标的示例:
在渲染方法中:
<i ref={(ref) => this.scrollIcon = ref} className="fa fa-2x fa-chevron-down"></i>
Run Code Online (Sandbox Code Playgroud)
在处理程序方法中:
if (this.scrollIcon !== null) {
if(($(document).scrollTop() + $(window).height() / 2) > ($('body').height() / 2)){
$(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-up');
}else{
$(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-down');
}
}
Run Code Online (Sandbox Code Playgroud)
添加/删除处理程序的方式与Austin提到的相同:
componentDidMount(){
window.addEventListener('scroll', this.handleScroll);
},
componentWillUnmount(){
window.removeEventListener('scroll', this.handleScroll);
},
Run Code Online (Sandbox Code Playgroud)
关于裁判的文件.
gio*_*pds 17
一个使用classNames,React钩子 useEffect,useState和styled-jsx 的例子:
import classNames from 'classnames'
import { useEffect, useState } from 'react'
const Header = _ => {
const [ scrolled, setScrolled ] = useState()
const classes = classNames('header', {
scrolled: scrolled,
})
useEffect(_ => {
const handleScroll = _ => {
if (window.pageYOffset > 1) {
setScrolled(true)
} else {
setScrolled(false)
}
}
window.addEventListener('scroll', handleScroll)
return _ => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
return (
<header className={classes}>
<h1>Your website</h1>
<style jsx>{`
.header {
transition: background-color .2s;
}
.header.scrolled {
background-color: rgba(0, 0, 0, .1);
}
`}</style>
</header>
)
}
export default Header
Run Code Online (Sandbox Code Playgroud)
小智 15
我的解决方案,用于制作响应式导航栏(位置:'相对',当不滚动并在滚动时固定而不是在页面顶部)
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll(event) {
if (window.scrollY === 0 && this.state.scrolling === true) {
this.setState({scrolling: false});
}
else if (window.scrollY !== 0 && this.state.scrolling !== true) {
this.setState({scrolling: true});
}
}
<Navbar
style={{color: '#06DCD6', borderWidth: 0, position: this.state.scrolling ? 'fixed' : 'relative', top: 0, width: '100vw', zIndex: 1}}
>
Run Code Online (Sandbox Code Playgroud)
对我来说没有性能问题.
Jea*_*sso 10
我发现除非成功传递true,否则无法成功添加事件侦听器:
componentDidMount = () => {
window.addEventListener('scroll', this.handleScroll, true);
},
Run Code Online (Sandbox Code Playgroud)
Ric*_*ard 10
使用 useEffect 的函数组件示例:
注意:您需要通过在 useEffect 中返回“清理”函数来移除事件侦听器。如果不这样做,每次组件更新时,您都会有一个额外的窗口滚动侦听器。
import React, { useState, useEffect } from "react"
const ScrollingElement = () => {
const [scrollY, setScrollY] = useState(0);
function logit() {
setScrollY(window.pageYOffset);
}
useEffect(() => {
function watchScroll() {
window.addEventListener("scroll", logit);
}
watchScroll();
// Remove listener (like componentWillUnmount)
return () => {
window.removeEventListener("scroll", logit);
};
}, []);
return (
<div className="App">
<div className="fixed-center">Scroll position: {scrollY}px</div>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
小智 7
如果您感兴趣的是滚动的子组件,那么这个示例可能会有所帮助:https : //codepen.io/JohnReynolds57/pen/NLNOyO?editors=0011
class ScrollAwareDiv extends React.Component {
constructor(props) {
super(props)
this.myRef = React.createRef()
this.state = {scrollTop: 0}
}
onScroll = () => {
const scrollTop = this.myRef.current.scrollTop
console.log(`myRef.scrollTop: ${scrollTop}`)
this.setState({
scrollTop: scrollTop
})
}
render() {
const {
scrollTop
} = this.state
return (
<div
ref={this.myRef}
onScroll={this.onScroll}
style={{
border: '1px solid black',
width: '600px',
height: '100px',
overflow: 'scroll',
}} >
<p>This demonstrates how to get the scrollTop position within a scrollable
react component.</p>
<p>ScrollTop is {scrollTop}</p>
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
我这里的赌注是使用具有新钩子的函数组件来解决它,但useEffect
我认为正确的选项不是像以前的答案那样使用,而是有useLayoutEffect
一个重要的原因:
该签名与 useEffect 相同,但它在所有 DOM 更改后同步触发。
这可以在React 文档中找到。如果我们使用useEffect
相反的方法并重新加载已经滚动的页面,则滚动将为 false 并且我们的类将不会被应用,从而导致不需要的行为。
一个例子:
import React, { useState, useLayoutEffect } from "react"
const Mycomponent = (props) => {
const [scrolled, setScrolled] = useState(false)
useLayoutEffect(() => {
const handleScroll = e => {
setScrolled(window.scrollY > 0)
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
}, [])
...
return (
<div className={scrolled ? "myComponent--scrolled" : ""}>
...
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
该问题的可能解决方案可能是https://codepen.io/dcalderon/pen/mdJzOYq
const Item = (props) => {
const [scrollY, setScrollY] = React.useState(0)
React.useLayoutEffect(() => {
const handleScroll = e => {
setScrollY(window.scrollY)
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
}, [])
return (
<div class="item" style={{'--scrollY': `${Math.min(0, scrollY/3 - 60)}px`}}>
Item
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
使用 React Hooks 更新答案
这是两个钩子 - 一个用于方向(向上/向下/无),一个用于实际位置
像这样使用:
useScrollPosition(position => {
console.log(position)
})
useScrollDirection(direction => {
console.log(direction)
})
Run Code Online (Sandbox Code Playgroud)
这里是钩子:
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)
})
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
153864 次 |
最近记录: |