【发布时间】:2025-11-23 07:55:02
【问题描述】:
我在页面的某个部分有一个计数器,当滚动到达该元素时,它只需要触发一次。我可以在 jQuery 中看到各种解决方案,但我正在寻找 react 或纯 javascript 方面的答案。
我使用状态和反应钩子实现了它,但即使我保留状态并使用条件语句,我也看到一些不稳定性一直触发不止一次。我不确定我哪里出错了。
这里是 react 类组件(由于使用 useEffect 时不断警告,我从函数切换到类)
更新:我找到了一个可行的解决方案,如下所示。如果有任何其他更好的方法可以做到这一点,请告诉我。
import React, { useState, useCallback, useEffect } from "react";
export default function DataCounter({ count, title }) {
const [number, setNumber] = useState(0);
const [trigger, setTrigger] = useState(false);
const increment = useCallback(() => {
const counter = (length = 2000) => {
setNumber(0);
let n = count;
let start = Date.now();
let end = start + length;
let interval = length / n;
const sInt = setInterval(() => {
let time = Date.now();
if (time < end) {
let count = Math.floor((time - start) / interval);
setNumber(count);
} else {
setNumber(n);
clearInterval(sInt);
}
}, interval);
};
counter();
}, [count]);
document.addEventListener("scroll", async () => {
const element = await document.getElementById("data");
const elementPosition = await element.getBoundingClientRect().top;
if (window.pageYOffset > elementPosition) setTrigger(true);
});
useEffect(() => {
if (trigger) {
increment();
}
}, [trigger, increment]);
return (
<div className="counter">
<div className="counter-number">{number}</div>
<p className="counter-title">{title}</p>
</div>
);
}
初始版本:
import React from "react";
export default class Counter extends React.Component {
state = {
number: 0,
loaded: false
};
increment(n, length = 2000){
this.setState({ number: 0 });
let start = Date.now();
let end = start + length;
let interval = length / n;
const sInt = setInterval(() => {
let time = Date.now();
if (time < end) {
let count = Math.floor((time - start) / interval);
this.setState({ number: count });
} else {
this.setState({ number: n });
clearInterval(sInt);
}
}, interval);
};
async handleScroll() {
const element = await document.getElementById("data");
const elementPosition = await element.getBoundingClientRect().bottom;
if (window.pageYOffset > elementPosition) {
if(!this.state.loaded) {
this.increment(100);
this.setState({ loaded: true });
}
return;
}
}
componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
}
render() {
return (
<div className="counter">
<div className="counter-number">{this.state.number}</div>
<p className="counter-title">{this.props.title}</p>
</div>
);
}
}
【问题讨论】:
-
我明白这一点:我在页面的某个部分有一个计数器,当滚动到达该元素时只能触发一次,但是你的 @987654323 @函数到底是干什么的?
-
它在 2 秒内将数字从 0 增加到 100,在这种情况下,我将值硬编码为 100。每当我到达页面上的特定元素时,我想触发这个
increment -
你能把你的功能组件和你的原始代码分开吗?覆盖让我的答案看起来很混乱
-
你的回答是对的。我缺少的是
this。此外,我添加了async以等待元素被加载,因为可以在组件完全加载之前完成滚动。谢谢。
标签: javascript reactjs counter