我想只在视口中的组件中做一些事情。它几乎可以工作,但我有一个我无法管理的问题。
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。
我希望通过方法返回每个可见元素时的情况。
它在我这样做时有效:
componentDidMount() {
setTimeout(() => {
if (this.isInViewPort()) {
console.log("I'm in viewport!");
}, 0);
}
但对于100%这不是一个好的解决方案。当我将此代码放在componentDidUpdate()的重构之后,它也不起作用。
这是反应生命周期的事情吗?我没有做任何巫婆状态,这就是为什么我不能理解。
我相信您的问题可能与您测试项目的位置以及如何提交文件等有关。我创建了一个小提琴来测试它:
.example {
width: 400px;
height: 90vh;
background-color: red;
border: 1px solid black;
}
https://jsfiddle.net/284Ldvkc/
我只将高度从400px改为90vh,所以我确保总是1在视野中,2在视野中有10%。
工作正常
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" />
在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上测试一下