滚动上的动画计数器未全部加载



我编写了下面的代码,以使动画计数器在窗口上可见时启动。当计数器都在同一行上可见时,它运行良好,但如果只有第一个可见,则此计数器将启动动画,但即使我们向下滚动,其他计数器也不会启动。第一个是完整的,但其他的仍然为零。

/* SCROLL FUNCTIONS */
// Every time the window is scrolled... 
$(window).scroll(function() {
// Check the location of each desired element
$('.counter').each(function(i) {
var bottom_of_object = $(this).offset().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
// If the object is completely visible in the window, fade it it
if (bottom_of_window > bottom_of_object) {
var $this = $(this);
$({
Counter: 0
}).animate({
Counter: $this.attr('data-to')
}, {
duration: 2000,
easing: 'swing',
step: function() {
$this.text(Math.ceil(this.Counter));
},
complete() {
$this.text(Math.ceil(this.Counter));
}
});
$(window).off("scroll");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col">
<div class="row counters text-dark">
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="counter" data-to="30000">0</div>
<label>Happy Clients</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="counter" data-to="15">0</div>
<label>Years in Business</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-sm-0">
<div class="counter" data-to="352">0</div>
<label>Cups of Coffee</label>
</div>
<div class="col-sm-6 col-lg-3">
<div class="counter" data-to="178">0</div>
<label>High Score</label>
</div>
</div>
</div>
</div>

问题是这行代码:

$(window).off("scroll");

您的离线呼叫将取消绑定所有事件,而不仅仅是一个事件。这意味着在第一个数字动画执行后,所有滚动事件绑定都将丢失。

要解决此问题,您需要分别绑定和解绑每个数字的动画。执行此操作的一种简单方法是为每个数字动画设置不同的功能,并分别绑定/取消绑定它们。一个通用示例:

var myScroll1 = function () {
$(window).off("scroll", myScroll1)
}
$(window).on("scroll", myScroll1)

请注意,我们只打开和关闭了这个特定的函数引用。您可以拥有其中的 4 个并分别打开和关闭它们。

编辑:这是您的脚本修改为工作,如解释:

var anim1 = function () { animateAndKill(1, $("#n1"), 3000, anim1); }
var anim2 = function () { animateAndKill(2, $("#n2"), 15,  anim2); }
var anim3 = function () { animateAndKill(3, $("#n3"), 352, anim3); }
var anim4 = function () { animateAndKill(4, $("#n4"), 178, anim4); }
// Every time the window is scrolled...
function animateAndKill(id, $number, max, myFunction) {
	var bottom_of_object = $number.offset().top + $number.outerHeight();
	var bottom_of_window = $(window).scrollTop() + window.innerHeight;
	
	// If the object is completely visible in the window, fade it it
	if (bottom_of_window > bottom_of_object) {
		$({ Counter: 0 }).animate({ Counter: max }, {
			duration: 2000,
			easing: 'swing',
			step: function () {
				var n = Math.ceil(this.Counter);
				$number.html(n);
			}
		});
		
		$(window).off("scroll", myFunction);
	}
}
$(window).on("scroll", anim1);
$(window).on("scroll", anim2);
$(window).on("scroll", anim3);
$(window).on("scroll", anim4);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="code.js"></script>
</head>
<body>
<div style="height: 1000px; background: #33FF44"></div>
<div class="row" style="z-index: 100; font-size: 100px;">
<div class="col">
<div class="row counters text-dark">
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div id="n1" class="counter" data-to="30000">0</div>
<label>Happy Clients</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div id="n2" class="counter" data-to="15">0</div>
<label>Years in Business</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-sm-0">
<div id="n3" class="counter" data-to="352">0</div>
<label>Cups of Coffee</label>
</div>
<div class="col-sm-6 col-lg-3">
<div id="n4" class="counter" data-to="178">0</div>
<label>High Score</label>
</div>
</div>
</div>
</div>
<div style="height: 3000px; background: #33FF44"></div>
</body>
</html>

https://jsfiddle.net/tyddlywink/pdvh4b3n/

摆脱$(window).off("scroll");位。 并跟踪谁已经被计算在内。

<div class="row">
<div class="col">
<div class="row counters text-dark">
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="counter" data-to="30000" data-counted='false'>0</div>
<label>Happy Clients</label>
</div>
<div style="height: 750px">
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="counter" data-to="15" data-counted='false'>0</div>
<label>Years in Business</label>
</div>
<div style="height: 750px">
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-sm-0">
<div class="counter" data-to="352" data-counted='false'>0</div>
<label>Cups of Coffee</label>
</div>
<div style="height: 750px">
</div>
<div class="col-sm-6 col-lg-3">
<div class="counter" data-to="178" data-counted='false'>0</div>
<label>High Score</label>
</div>
</div>
</div>
</div>

Javascript:

// Every time the window is scrolled... 
$(window).scroll(function() {
// Check the location of each desired element
$('.counter').each(function(i) {
var bottom_of_object = $(this).offset().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
var counted = $(this).data("counted");

// If the object is completely visible in the window, fade it it
if (!counted && bottom_of_window > bottom_of_object) {
$(this).data("counted", true);
var $this = $(this);
$({
Counter: 0
}).animate({
Counter: $this.attr('data-to')
}, {
duration: 2000,
easing: 'swing',
step: function() {
$this.text(Math.ceil(this.Counter));
},
complete() {
$this.text(Math.ceil(this.Counter));
}
});
}
});
});

/*
	SCROLL FUNCTIONS
	********************************/
	// Every time the window is scrolled... 
	$(window).scroll(function () {

// Check the location of each desired element
		$('.count').each(function (i) {
			var bottom_of_object = $(this).offset().top + $(this).outerHeight();
			var bottom_of_window = $(window).scrollTop() + $(window).height();
			// If the object is completely visible in the window, fade it it
			if (bottom_of_window > bottom_of_object) {
				var $this = $(this);
				$({
					Counter: 0
				}).animate({
					Counter: $this.attr('data-to')
				}, {
					duration: 2000,
					easing: 'swing',
					step: function () {
						$this.text(Math.ceil(this.Counter));
					},
complete(){
$this.text(Math.ceil(this.Counter));
}
				});
$(this).removeClass('count').addClass('counted');
			}
		}); 

	});
<div class="row">
<div class="col">
<div class="row counters text-dark">
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="count" data-to="30000">0</div>
<label>Happy Clients</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-lg-0">
<div class="count" data-to="15">0</div>
<label>Years in Business</label>
</div>
<div class="col-sm-6 col-lg-3 mb-4 mb-sm-0">
<div class="count" data-to="352">0</div>
<label>Cups of Coffee</label>
</div>
<div class="col-sm-6 col-lg-3">
<div class="count" data-to="178">0</div>
<label>High Score</label>
</div>
</div>
</div>
</div>

侦听滚动事件对性能不友好,你真的应该考虑使用Intersection Observer 来处理这样的事情。

首先,您必须创建一个新的观察器:

var options = {
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);

在这里,我们定义,一旦您的目标元素在视口中 100% 可见(阈值为 1),您的回调函数就会被执行。在这里您可以定义另一个百分比,0.5 表示一旦您的元素可见 50%,该函数就会被执行。

然后,您必须定义要监视的元素,在您的情况下,这将是counter元素:

var target = document.querySelector('.counter');
observer.observe(target);

最后,您需要通过定义回调函数来指定元素在视口中可见后应该发生的情况:

var callback = function(entries, observer) { 
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// here you animate the counter
});
};

在您的特定情况下,您可能不会遇到性能问题,但是如果您有越来越多的元素,您将开始注意到一些东西。因此,如果您再次遇到此问题,最好知道这一点并"做对"。

如果您需要支持较旧的浏览器,请使用 w3c 中的官方 polyfill。

如果您不需要元素,也可以从任何元素中删除观察器,

其中

最新更新