javascript 等效于 React、onScroll 中的 document.querySelectorAll()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49344348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Equivalent of document.querySelectorAll() in React, onScroll
提问by Giovanni
What's the equivalent of document.querySelectorAll('.classname')in React? I understand I should use Refs, but how dow I observe multiple Refs onScroll?
document.querySelectorAll('.classname')React 中的等价物是什么?我知道我应该使用 Refs,但是我如何观察多个 RefsonScroll呢?
I usually use a function like the one below to check the viewport position of multiple elements in the page, and trigger different css animation when each element enters the viewport:
我通常使用类似下面这样的函数来检查页面中多个元素的视口位置,并在每个元素进入视口时触发不同的css动画:
HTML
HTML
<ul>
<li data-position="below-viewport"></li>
<li data-position="below-viewport"></li>
<li data-position="below-viewport"></li>
<li data-position="below-viewport"></li>
</ul>
Javascript
Javascript
getPosition: function (element) {
const rect = element.getBoundingClientRect();
if ((rect.top > -1) && (rect.top < (window.innerHeight * 0.75))) {
element.setAttribute('data-js-position','in-viewport');
} else if ((rect.top > 0) && (rect.top < window.innerHeight)) {
element.setAttribute('data-js-position','entering-viewport');
} else if (rect.top > window.innerHeight) {
element.setAttribute('data-js-position','below-viewport');
} else if (rect.bottom < 0) {
element.setAttribute('data-js-position','above-viewport');
}
}
window.addEventListener('scroll', function() {
[].forEach.call(document.querySelectorAll('[data-js-position]'), el => {
positionChecker.getPosition(el);
})
});
How would I implement something similar in React? Can you give me an example of a function that observes multiple divs in React?
我将如何在 React 中实现类似的东西?你能举一个在 React 中观察多个 div 的函数的例子吗?
Even better: how can I abstract this function in App.js, so that I can use it also in child Components?
更好的是:我怎样才能在 中抽象这个函数App.js,以便我也可以在子组件中使用它?
回答by Andrew
Make each lihtml element its own component and hold a refreference to it in its own state.
使每个lihtml 元素成为自己的组件,并ref在其自己的状态下保存对它的引用。
class LiElement extends React.Component {
componentDidMount() {
this.ref.getPosition()
}
render() {
return (
<li ref={(ctx) => this.ref = ctx}>
</li>
)
}
}
回答by Ignacio
Iterating through refs might get you something similar to what you're trying to achieve.
遍历 refs 可能会得到类似于你想要实现的东西。
In this example I'm storing every node in a local Map so you can iterate through them and get their getBoundingClientRect.
在本例中,我将每个节点存储在本地 Map 中,以便您可以遍历它们并获取它们的 getBoundingClientRect。
Note, that there are several ways of doing this, you don't have to create a Map, you can just get each element's "ref", but you would have to assign a different "ref" value to each "li".
请注意,有几种方法可以做到这一点,您不必创建 Map,您只需获取每个元素的“ref”,但您必须为每个“li”分配不同的“ref”值。
Also, it would be a good idea to throttle the handleScroll call..
此外,最好限制 handleScroll 调用。.
class App extends React.Component {
constructor(props) {
super(props);
this._nodes = new Map();
}
componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
}
handleScroll = e => {
Array.from(this._nodes.values())
// make sure it exists
.filter(node => node != null)
.forEach(node => {
this.getPosition(node);
});
};
getPosition = node => {
const rect = node.getBoundingClientRect();
// do something cool here
console.log("rect:", rect);
};
componentWillUnmount() {
window.removeEventListener("scroll", this.handleScroll);
}
render() {
return (
<div>
<ul>
<li key="1" ref={c => this._nodes.set(1, c)}>
Your thing 1
</li>
<li key="2" ref={c => this._nodes.set(2, c)}>
Your thing 2
</li>
<li key="3" ref={c => this._nodes.set(3, c)}>
Your thing 3
</li>
</ul>
</div>
);
}
}
回答by Giovanni
Adding this other possible solution: creating a new react component VisibilitySensor, so to use only one ref and only one function
添加另一种可能的解决方案:创建一个新的反应组件VisibilitySensor,因此只使用一个引用和一个函数
import React, { Component } from 'react';
class VisibilitySensor extends Component {
componentDidMount() {
window.addEventListener('scroll', this.getElementPosition = this.getElementPosition.bind(this));
this.getElementPosition();
}
componentWillUnmount() {
window.removeEventListener('scroll', this.getElementPosition);
}
getElementPosition() {
const element = this.visibilitySensor;
var rect = element.getBoundingClientRect();
if ((rect.top > 0) && (rect.top < (window.innerHeight * 0.75))) {
element.setAttribute("data-position","in-viewport");
} else if (rect.top > window.innerHeight) {
element.setAttribute("data-position","below-viewport");
} else if (rect.bottom < 0) {
element.setAttribute("data-position","above-viewport");
}
}
render() {
return (
<div data-position="below-viewport" ref={(element) => { this.visibilitySensor = element; }}>
{this.props.children}
</div>
);
}
}
export default VisibilitySensor;
Then wrapping every li(or div) I need to watch with the above component. I personally ended up disliking the solution above, because the new added divwould mess up with my css styling, particularly width of child related to width of parent, etc..
然后用上面的组件包装我需要观看的每个li(或div)。我个人最终不喜欢上面的解决方案,因为新添加的内容div会弄乱我的 css 样式,尤其是与父项宽度相关的子项宽度等。
<ul>
<VisibilitySensor>
<li></li>
</VisibilitySensor>
<VisibilitySensor>
<li></li>
</VisibilitySensor>
<VisibilitySensor>
<li></li>
</VisibilitySensor>
<VisibilitySensor>
<li></li>
</VisibilitySensor>
</ul>

