英文:
Using Intersection Observer to target the same class at different times throughout the page
问题
有各种动态计数器分布在页面中,它们在首次出现在浏览器视口内时需要计数到指定的数字。
以下代码有效,但会同时激活所有计数器(即使不可见)。
我不确定我做错了什么?
<script>
jQuery(document).ready(function($){
function startCounter(){
$('.counter').each(function() {
var num = jQuery(this), countTo = num.attr("data-count");
var decimal = 0;
if (countTo.indexOf(".") > 0) {
decimal = countTo.toString().split(".")[1].length;
}
$({ countNum: num.text()}).animate({ countNum: countTo }, {
duration: 3000, easing:"swing", step: function() {
num.text(parseFloat(this.countNum).toFixed(decimal));
//num.text(Math.floor(this.countNum));
}, complete: function() {
num.text(this.countNum);
}
});
});
}
let counters = document.querySelectorAll('.counter');
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
startCounter();
//observer.unobserve(entry.target);
}
});
},
{ threshold: 1 }
);
counters.forEach(counter => {
observer.observe(counter);
});
});
</script>
<body>
<div class="counter" data-count="1000.45"></div><div class="counter" data-count="2306.33"></div>
<div style="height:100vh;"></div>
<div class="counter" data-count="98"></div>
<div class="counter" data-count="560"></div>
</body>
英文:
I've got various animated counters throughout a page which need to count up to the specified number when they each become visible for the first time within the browser viewport.
The following code works but activates all of the counters at the same time (even when not visible).
I'm not sure what I'm doing wrong?
<script>
jQuery(document).ready(function($){
function startCounter(){
$('.counter').each(function() {
var num = jQuery(this), countTo = num.attr("data-count");
var decimal = 0;
if (countTo.indexOf(".") > 0) {
decimal = countTo.toString().split(".")[1].length;
}
$({ countNum: num.text()}).animate({ countNum: countTo }, {
duration: 3000, easing:"swing", step: function() {
num.text(parseFloat(this.countNum).toFixed(decimal));
//num.text(Math.floor(this.countNum));
}, complete: function() {
num.text(this.countNum);
}
});
});
}
let counters = document.querySelectorAll('.counter');
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
startCounter();
//observer.unobserve(entry.target);
}
});
},
{ threshold: 1 }
);
counters.forEach(counter => {
observer.observe(counter);
});
});
</script>
<body>
<div class="counter" data-count="1000.45"></div><div class="counter" data-count="2306.33"></div>
<div style="height:100vh;"></div>
<div class="counter" data-count="98"></div>
<div class="counter" data-count="560"></div>
</body>
答案1
得分: 1
你在startCounter
函数中通过使用$('.counter').each(function()
来针对所有类为'counter'的元素进行操作。
因此,对于观察器中的每个条目,即如果任何条目在DOM上变为可见,则所有元素(即计数器)都会受到影响。
你只需针对在DOM上可见的条目(即isIntersecting
为true的条目)进行操作,建议将该特定元素(entry.target
)作为参数传递给startCounter
,并仅对该特定元素进行必要的更改。
英文:
You are targeting all the elements with the class 'counter' in startCounter function by using $('.counter').each(function()
.
So for each entry in your observer, i.e if any of the entries become visible on DOM, all the elements (i.e counters) get affected.
You only have to target the entry which is visible (i.e isIntersecting) on DOM, so it is suggested that you pass that particular element(entry.target) as an argument to startCounter, and only make the necessary changes on that particular element
答案2
得分: 0
感谢 @Say1218 指导我正确的方向,现在以下部分完美运行。
我遗漏的部分是我需要仅针对特定的 entry.target
当它出现在视图中时。
所以我告诉 new IntersectionObserver
在每个 entry.target
可见时添加一个类 .countup
,例如:
entry.target.classList.add('countup');
let images = document.querySelectorAll('.counter');
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 给当前 entry-target 添加一个 .countup 类
entry.target.classList.add('countup');
countUp();
observer.unobserve(entry.target);
console.log(entry.target);
}
});
},
{ threshold: 1 }
);
images.forEach(image => {
observer.observe(image);
});
然后在 countUp()
函数中,我告诉它应用于所有具有类 .countup.counter
的 div 元素。
function countUp() {
$('.countup.counter').each(function() {
var num = jQuery(this), countTo = num.attr("data-count");
var decimal = 0;
if (countTo.indexOf(".") > 0) {
decimal = countTo.toString().split(".")[1].length;
}
$({ countNum: num.text()}).animate({ countNum: countTo }, {
duration: 3000, easing:"swing", step: function() {
num.text(parseFloat(this.countNum).toFixed(decimal));
}, complete: function() {
num.text(this.countNum);
}
});
});
}
但因为初始的 HTML 保持不变,只有在 IntersectionObserver
添加了 .countup
类之后,countUp()
函数才会触发一次。
<div class="counter" data-count="1000.45" data-speed="20"></div>
<div class="counter" data-count="96.25" data-speed="20"></div>
<div class="counter" data-count="34" data-speed="20"></div>
<div style="height:100vh;"></div>
<div class="counter" data-count="10000" data-speed="20"></div>
聪明极了!这让我头痛了一段时间。
英文:
Thanks to @Say1218 who pointed me in the right direction, below now works perfectly.
The thing I was missing was I needed to target only the specific entry.target
when it came into view.
So I told new IntersectionObserver
to add a class of .countup
when each entry.target
became visible e.g.
entry.target.classList.add('countup');
let images = document.querySelectorAll('.counter');
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// add a class of .countup to the current entry-target
entry.target.classList.add('countup');
countUp();
observer.unobserve(entry.target);
console.log(entry.target);
}
});
},
{ threshold: 1 }
);
images.forEach(image => {
observer.observe(image);
});
Then in the countUp()
function, I told it to apply for all divs with the class .countup.counter
function countUp() {
$('.countup.counter').each(function() {
var num = jQuery(this), countTo = num.attr("data-count");
var decimal = 0;
if (countTo.indexOf(".") > 0) {
decimal = countTo.toString().split(".")[1].length;
}
$({ countNum: num.text()}).animate({ countNum: countTo }, {
duration: 3000, easing:"swing", step: function() {
num.text(parseFloat(this.countNum).toFixed(decimal));
}, complete: function() {
num.text(this.countNum);
}
});
});
}
But because the initial HTML remained as before, the countUp()
function was only triggered once IntersectionObserver
had added the class of .countup
<div class="counter" data-count="1000.45" data-speed="20"></div>
<div class="counter" data-count="96.25" data-speed="20"></div>
<div class="counter" data-count="34" data-speed="20"></div>
<div style="height:100vh;"></div>
<div class="counter" data-count="10000" data-speed="20"></div>
Ingenious lol! That was a head scratcher for a while
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论