我只想在视口中的组件中做某事。它几乎可以正常工作,但是我有一个无法解决的问题。
class Hello extends React.Component {
componentDidMount() {
console.log(this.isInViewPort()) // false for second element - last in viewport
if (this.isInViewPort()) {
console.log("I'm in viewport!");
}
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
isInViewPort = () => {
const element = this.refs[this.props.id];
const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
const result = rect.top <= windowHeight && rect.top + rect.height >= 0;
return result;
}
handleScroll = () => {
if (this.isInViewPort()) {
console.log("I'm in viewport!");
}
}
render() {
return (
<div className="example" ref={this.props.id} onClick={this.handleScroll} /> // onClick added for tests
);
}
}
class App extends React.Component {
render() {
return (
<Hello id={1} />
<Hello id={2} />
<Hello id={3} />
);
}
}
.example {
width: 400px;
height: 400px;
background-color: red;
}
加载页面时,视口中有两个元素。第一个-视口中的100%,第二个-视口中的15-20%。
在此示例中,我只有一个console.log,因此this.isInViewPort()仅对第一个元素为true。是错误的,因为其中两个可见。
当我触摸事件滚动时,该组件将立即显示为方法并显示控制台日志。当我不触摸滚动条,而是单击第二个组件(这是为了测试而添加)时,方法返回true,我得到console.log。
我想让每个可见元素都通过方法返回true的情况。
当我这样做时它会起作用:
componentDidMount() {
setTimeout(() => {
if (this.isInViewPort()) {
console.log("I'm in viewport!");
}, 0);
}
但是对于100%而言,这不是一个好的解决方案。当我将此代码重构为componentDidUpdate()后,它也无法正常工作。
这与反应生命周期有关吗?我没有做任何巫婆状态,这就是为什么它对我来说是无法理解的。
答案 0 :(得分:1)
行得通
class Hello extends React.Component {
componentDidMount() {
this.isInViewPort()
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
isInViewPort = () => {
const element = this.refs[this.props.id];
const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
const result = rect.top <= windowHeight && rect.top + rect.height >= 0;
this.props.onLog(result ? `${this.props.id} in view port` : `${this.props.id} outside`)
return result;
}
handleScroll = () => {
this.isInViewPort()
}
render() {
return (<div className="example" ref={this.props.id} onClick={this.handleScroll} />
);
}
}
class App extends React.Component {
render() {
return <div>
<Hello id={1} onLog={console.info} />
<Hello id={2} onLog={console.info} />
<Hello id={3} onLog={console.info} />
</div>;
}
}
ReactDOM.render(<App /> ,
document.getElementById('container')
);
.example {
width: 400px;
height: 400px;
background-color: red;
}
.example:first-child {
background-color: pink;
}
.example:last-child {
background-color: blue;
}
.as-console-wrapper {
height: 62px!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container" />
答案 1 :(得分:1)
我相信您的问题可能与您在哪里测试项目以及如何交付文件等有关。 我创建了一个小提琴来对其进行测试:
(tr,test) = dataframe.randomSplit([0.8,0.2]), seed = 23)
https://jsfiddle.net/284Ldvkc/
我只将高度从400px更改为90vh,所以我要确保始终以1%的比例显示1,以2%的比例显示2。
答案 2 :(得分:1)
在StackOverflow中,您可以找到检查“ DOM element is visible in the current viewport”的最佳方法。
我刚刚添加了一个:
isElementInViewport = el => {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <=
(window.innerHeight ||
document.documentElement.clientHeight) /*or $(window).height() */ &&
rect.right <=
(window.innerWidth ||
document.documentElement.clientWidth) /*or $(window).width() */
);
};
并从以下位置调用它:
isInViewPort = () => {
const element = this.refs[this.props.id];
console.log("isInViewPort:" + this.props.id);
return this.isElementInViewport(element);
};
您可以在codesandbox.io
上对此进行测试