使用交叉观察器在页面的不同时间目标同一类。

huangapple go评论51阅读模式
英文:

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(&#39;countup&#39;);

			let images = document.querySelectorAll(&#39;.counter&#39;);
let observer = new IntersectionObserver(
(entries, observer) =&gt; {
entries.forEach((entry) =&gt; {
if (entry.isIntersecting) {
// add a class of .countup to the current entry-target
entry.target.classList.add(&#39;countup&#39;);
countUp();
observer.unobserve(entry.target);
console.log(entry.target);
}
});
},
{ threshold: 1 }
);
images.forEach(image =&gt; {
observer.observe(image);
});

Then in the countUp() function, I told it to apply for all divs with the class .countup.counter

			function countUp() {
$(&#39;.countup.counter&#39;).each(function() {
var num = jQuery(this), countTo = num.attr(&quot;data-count&quot;);
var decimal = 0;
if (countTo.indexOf(&quot;.&quot;) &gt; 0) { 
decimal = countTo.toString().split(&quot;.&quot;)[1].length; 
}
$({ countNum: num.text()}).animate({ countNum: countTo }, {
duration: 3000, easing:&quot;swing&quot;, 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

		&lt;div class=&quot;counter&quot; data-count=&quot;1000.45&quot; data-speed=&quot;20&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;counter&quot; data-count=&quot;96.25&quot; data-speed=&quot;20&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;counter&quot; data-count=&quot;34&quot; data-speed=&quot;20&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;height:100vh;&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;counter&quot; data-count=&quot;10000&quot; data-speed=&quot;20&quot;&gt;&lt;/div&gt;

Ingenious lol! That was a head scratcher for a while

huangapple
  • 本文由 发表于 2023年3月8日 17:45:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75671465.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定