元素在视口中时重新启动计数器动画



这段代码使计数器/动画在视图中启动,但我希望它在滚动出视图后再次进入视图时重新启动。似乎无法解决。

如果你想在这里看到它的实时链接-向下滚动到页脚之前的底部。https://easyrecycle.dk/Serviceomraader.html

var a = 0;
$(window).scroll(function() {
var oTop = $('#counter').offset().top - window.innerHeight;
if (a == 0 && $(window).scrollTop() > oTop) {
$('.counter-value').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 3000,
easing: 'swing',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
}
});
});
a = 1;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="counter">
<div class="counter-container">
<div class="counter-box">
<div class="counter-value" data-count="30">0</div>
<span></span>
<p>Antal medarbejdere</p>
</div>
<div class="counter-box">
<div class="counter-value" data-count="51000">0</div>
<span></span>
<p>Processeret udstyr i KG pr. md.</p>
</div>
<div class="counter-box">
<div class="counter-value" data-count="51">0</div>
<span></span>
<p>Antal afhentninger pr. md.</p>
</div>
</div>
</div>

不要使用.scroll()事件侦听器。这是一个性能杀手。JavaScript的";滚动";EventListener-如果用于执行繁重的任务。实际上,您根本不需要jQuery。

你的任务基本上涉及使用:

  • 交叉点观察者API来观察进入/离开视口的元素,而不是您使用的非常昂贵的滚动侦听器
  • counterStart()函数(在进入视口时触发(,它使用requestAnimationFrame——这是处理网络上动画的最高效的方式
  • counterStop()函数(在视口退出时触发(,该函数取消AnimationFrame并将元素计数器重置回其start
  • 一个宽松函数,在该函数中,您将传递线性映射的时间分数(float0.0 ... 1.0(,以便检索用于导出整数/计数器的宽松值

//gist.github.com/gre/1650294
const easeInOutQuad = (t) => t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
const inViewportCounter = (el) => {
const duration = +el.dataset.duration || 3000;
const start = +el.textContent || 0;
const end = +el.dataset.count || 100;
let raf;
//stackoverflow.com/a/70746179/383904
const counterStart = () => {
if (start === end) return; // If equal values, stop here.
const range = end - start;
let curr = start; // Set current to start
const timeStart = Date.now();
const loop = () => {
let elaps = Date.now() - timeStart;
if (elaps > duration) elaps = duration;
const frac = easeInOutQuad(elaps / duration); // Get the time fraction with easing
const step = frac * range; // Calculate the value step
curr = start + step; // Increment or Decrement current value
el.textContent = Math.trunc(curr); // Apply to UI as integer
if (elaps < duration) raf = requestAnimationFrame(loop); // Loop
};
raf = requestAnimationFrame(loop); // Start the loop!
};
const counterStop = (el) => {
cancelAnimationFrame(raf);
el.textContent = start;
};
//stackoverflow.com/a/70746179/383904
const inViewport = (entries, observer) => {
entries.forEach(entry => {
// Enters viewport:
if (entry.isIntersecting) counterStart(entry.target);
// Exits viewport:
else counterStop(entry.target);
});
};
const Obs = new IntersectionObserver(inViewport);
const obsOptions = {}; //developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options
// Attach observer to element:
Obs.observe(el, obsOptions);
};
document.querySelectorAll('[data-count]').forEach(inViewportCounter);
[data-count] { margin: 55vh 0; font: 3rem/1.4 sans-serif; }
Scroll down...
<div data-count="300">0</div>
<div data-count="51000">0</div>
<div data-count="1000">0</div>

为了更好地理解以上主要的两块代码,我将它们的原始基本答案进行了重新使用和调整:

  • 从开始到结束设置计数器动画
  • CSS3动画元素(如果在视口中可见((页面滚动(

基本差异为:

  • counter函数中,我将时间的线性分数传递给了放松函数
  • 对于交叉点观测器,我使用了if .. else块;用于将元件的CCD_ 9复位回"0"的CCD_;0";(或任何start值(

很抱歉没有像几年前那样使用jQuery,但希望你能学到一些令人兴奋的新东西。如果某些部分不完全清楚,请随时询问。

正如您从下面的示例中看到的,我添加了一个简单的if(如果不在视图中(并重置text/变量。

var a = 0;
$(window).scroll(function() {
var oTop = $('#counter').offset().top - window.innerHeight;
if (a == 0 && $(window).scrollTop() > oTop) {
$('.counter-value').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 3000,
easing: 'swing',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
}
});
});
a = 1;
} else {
$('.counter-value').text('0');
a = 0;
}
});
.fakespace{
height:500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='fakespace'></div>
<div id="counter">
<div class="counter-container">
<div class="counter-box">
<div class="counter-value" data-count="30">0</div>
<span></span>
<p>Antal medarbejdere</p>
</div>
<div class="counter-box">
<div class="counter-value" data-count="51000">0</div>
<span></span>
<p>Processeret udstyr i KG pr. md.</p>
</div>
<div class="counter-box">
<div class="counter-value" data-count="51">0</div>
<span></span>
<p>Antal afhentninger pr. md.</p>
</div>
</div>
</div>

最新更新