检查页面滚动何时到达多个不同的div,将计数器从0动画设置为文本元素



我需要检查页面滚动何时到达特定的不同div,然后开始对svg饼图和渐进百分比数字进行动画处理。

我从容器元素的每个 H3 中的文本插入中获取百分比值,然后创建内容元素,并使用此变量设置 svg animate 标签的"to"属性和计数器的跨度文本。

在滚动页面上,我调用"go"函数来启动svg动画,然后启动计数器动画。

页面测试在这里

我有两个问题:

1-所有动画在到达第一个div容器时同时开始,我希望每个动画在页面滚动到达相应的容器时开始;

2-即使渐进式数字动画在动画开始之前从 0 开始,它也会显示最终值。 有人可以帮助我吗?

//// JQUERY
$(document).ready(function(){
$(".phps_contenuti_pagina").each(function () {
hit_elem =  $(this);
//var for getting the percentage number from h3
number_perc = $(this).children("h3").text().replace(/[^0-9]/gi, '');
//I create the html element with span and svg tags and I use the var above for settin the span text and the "to" animate attr
$(this).append('<div><span class="count">'+number_perc+'%</span><svg  width="300" height="300"viewbox="0 0 400 400"><defs><clipPath id="counter-clippath"><rect x="50" y="0" width="320" height="72" /></clipPath></defs><circle fill="#ccc" cx="200" cy="200" r="200" /><circle cx="200" cy="200" r="160" transform="rotate(-90, 200, 200)" stroke-dasharray="0, 1000" stroke="#7cb342" stroke-width="80" data-fallback="edge"><animate attributeName="stroke-dasharray" dur="1s" to="'+number_perc+'0,1000" fill="freeze" begin="indefinite" /></circle><circle cx="200" cy="200" r="160" fill="#fff" /></svg></div></div>')
});
});     
//function to start the svg animation
function go () {
var elements = document.getElementsByTagName("animate");
for (var i = 0; i < elements.length; i++) {
elements[i].beginElement();
}
}
//I call the above funtcion when page scroll reach container elements and then i start the counter animation
$(window).on('scroll',function() {
var hT = hit_elem.offset().top,
hH = hit_elem.outerHeight(),
wH = $(window).height(),
wS = $(this).scrollTop();
if (wS > (hT + hH - wH)) {
//call go function
go();
//I switch off the scroll function to prevent the animation from continue running
$(window).off('scroll');
//counter animation
$('.count').each(function() {
$(this).prop('Counter', 0).animate({
Counter: $(this).text()
}, {
duration: 900,
easing: 'swing',
step: function(now) {
$(this).text(Math.ceil(now));
}
});
});
}
});
/* CSS */
body{margin-top:50vh;margin-bottom:200vh;}
.phps_contenuti_pagina{display:inline-block;width:100%;}
.phps_contenuti_pagina > div{ float:left;position:relative;}
span.count{width:200px;height:100px;position:absolute;top:100px;left:50px;font-size:100px;text-align:center;}
<!--HTML-->
<div class="phps_contenuti_pagina">
<h3>Lorem 40%</h3>
<div>Bla bla bla</div>
</div>
<div class="phps_contenuti_pagina">
<h3>Ipsum 20%</h3>
<div>Bla bla bla</div>
</div>

我尝试为每个容器设置渐进式 id 号,并在设置容器 .offset((.top 和 .outerHeight(( vars 时使用它们,但它不起作用。

我尝试将百分比值设置为 0,然后调用计数器函数之前的"number_perc"var,但它只给了我最后一个div 容器的百分比数

最好的解决方案是使用交叉观察器(IO(。使用此方法比侦听滚动事件的性能更高。IO 的作用是:当观察元素位于视口中(基于您提供的设置(或离开视口时,它会查看一个元素并触发一个函数。

首先,必须定义 IO 的选项并对其进行初始化:

let options = {
rootMargin: '5px 10px', // works just like margin on element
threshold: 0.9 // when ~90% of element is visible, trigger IO
}
let observer = new IntersectionObserver(callback, options); // trigger callback function when provided options match for an element

然后,您必须定义要监视的元素:

let targets = document.querySelectorAll('.inactive'); // you want to watch multiple elements with inactive class
targets.forEach(target => { // loop through your elements
observer.observe(target); // observe them
});
// the callback we setup for the observer will be executed now for the first time
// it waits until we assign a target to our observer (even if the target is currently not visible)

最后一步是定义观察元素到达视口后应该发生的情况:

let callback = (entries, observer) => {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
//   entry.boundingClientRect...
// Your .inactive element is in viewport.
});
};

当您只需要触发一次时,您也可以取消观察元素。

来自 w3c 的填充代码存在以支持不支持 IO (IE11( 的浏览器。

非常感谢保罗·勒博 经过一些测试,我做到了!

所以我删除了"hit_elem"var,并为所有div 元素设置了一个".inactive"类。

在滚动事件处理程序中,我为".inactive"divs设置了一个每个函数,在其中我创建了".offset.top,outerHeight,window.height和window.scroll"变量,用于检查page_scroll何时到达此元素,然后为每个元素删除"非活动"并添加"active"类。

通过这种方式,我可以仅为.active animate 元素调用"go"函数,并仅为 .active.count span创建计数器。

//// JQUERY
$(document).ready(function() {
$(".phps_contenuti_pagina").each(function() {
//var for getting the percentage number from h3
number_perc = $(this).children("h3").text().replace(/[^0-9]/gi, '');
//I create the html element with span and svg tags and I use the var above for settin the span text and the "to" animate attr
$(this).append('<div><span class="count">' + number_perc + '%</span><svg  width="300" height="300"viewbox="0 0 400 400"><defs><clipPath id="counter-clippath"><rect x="50" y="0" width="320" height="72" /></clipPath></defs><circle fill="#ccc" cx="200" cy="200" r="200" /><circle cx="200" cy="200" r="160" transform="rotate(-90, 200, 200)" stroke-dasharray="0, 1000" stroke="#7cb342" stroke-width="80" data-fallback="edge"><animate attributeName="stroke-dasharray" dur="1s" to="' + number_perc + '0,1000" fill="freeze" begin="indefinite" /></circle><circle cx="200" cy="200" r="160" fill="#fff" /></svg></div></div>')
});
//set inactive class to every phps_contenuti_pagina 
$(".phps_contenuti_pagina").addClass("inactive");
});
//function to start the svg animation
function go() {
var elements = $(".active animate");
for (var i = 0; i < elements.length; i++) {
elements[i].beginElement();
}
}
//Scroll function for start animations when each element is reached
$(window).on('scroll', function() {
$(".inactive").each(function() {
hT = $(this).offset().top,
hH = $(this).outerHeight(),
wH = $(window).height(),
wS = $(window).scrollTop();
if (wS > (hT + hH - wH)) {
$(this).removeClass("inactive");
//prevent any active class setted before by remove it on every phps_contenuti_pagina div
$(".phps_contenuti_pagina").removeClass("active");
//set the active class only for this phps_contenuti_pagina
$(this).addClass("active");
//call go function
go();
//counter animation only for active phps_contenuti_pagina span
$(".active .count").each(function() {
$(this).prop('Counter', 0).animate({
Counter: $(this).text()
}, {
duration: 900,
easing: 'swing',
step: function(now) {
$(this).text(Math.ceil(now) + "%");
}
});
});
}
});
});
body {
margin-top: 1000px;
margin-bottom: 200vh;
}
.phps_contenuti_pagina {
display: inline-block;
width: 100%;
}
.phps_contenuti_pagina>div {
float: left;
position: relative;
}
span.count {
width: 200px;
height: 100px;
position: absolute;
top: 100px;
left: 50px;
font-size: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div class="phps_contenuti_pagina">
<h3>Lorem 40%</h3>
<div>Bla bla bla</div>
</div>
<div class="phps_contenuti_pagina">
<h3>Ipsum 20%</h3>
<div>Bla bla bla</div>
</div>

有那么好吗?我不是一个好的程序员,你能给我一些建议,使这段代码更好吗?

现在仍然是第二个问题,我需要计数器编号显示第一个零,现在它显示最终值。 我尝试在使用 append 方法构建的 html 中将值设置为零,然后尝试从每个函数中取出变量"number_perc">,但我知道由于范围的原因我不能这样做。

我一直在研究它,也许我可以自己解决它,但任何建议都可以不胜感激。

最新更新