<ul class="scroll-anim-21" id="js-scroll-anim-21">
<li class="scroll-anim-21__item">
<h3 class="scroll-anim-21__heading">プロジェクト</h3>
<p class="scroll-anim-21__number"><span class="scroll-anim-21__count" data-count="123">0</span>件以上</p>
</li>
<li class="scroll-anim-21__item">
<h3 class="scroll-anim-21__heading">顧客満足度</h3>
<p class="scroll-anim-21__number"><span class="scroll-anim-21__count" data-count="70">0</span>%</p>
</li>
<li class="scroll-anim-21__item">
<h3 class="scroll-anim-21__heading">現在のプロジェクト</h3>
<p class="scroll-anim-21__number"><span class="scroll-anim-21__count" data-count="15">0</span>件</p>
</li>
<li class="scroll-anim-21__item">
<h3 class="scroll-anim-21__heading">経験年数</h3>
<p class="scroll-anim-21__number"><span class="scroll-anim-21__count" data-count="5">0</span>年</p>
</li>
</ul>
ul.scroll-anim-21#js-scroll-anim-21
each item in items
li.scroll-anim-21__item
h3.scroll-anim-21__heading #{ item.heading }
p.scroll-anim-21__number
span.scroll-anim-21__count( data-count=item.count ) 0
| #{ item.unit }
{
"items": [
{
"heading": "プロジェクト",
"count": 123,
"unit": "件以上"
},
{
"heading": "顧客満足度",
"count": 70,
"unit": "%"
},
{
"heading": "現在のプロジェクト",
"count": 15,
"unit": "件"
},
{
"heading": "経験年数",
"count": 5,
"unit": "年"
}
]
}
$BLOCK_NAME: '.scroll-anim-21';
#{ $BLOCK_NAME } {
@include Mq(md) {
display: flex;
}
&__item {
display: flex;
flex-direction: column;
flex-grow: 1;
align-items: center;
justify-content: center;
margin-bottom: 16px;
@include Mq(md) {
margin-bottom: 0;
}
}
&__number {
font-size: 24px;
font-weight: bold;
}
}
'use strict';
export const scrollAnim21 = () => {
const anim = new Anim21('js-scroll-anim-21');
anim.init();
}
class Anim21 {
el: HTMLElement;
numEl: NodeListOf<HTMLElement>;
countTime: number;
countInterval: number;
constructor(elId: string) {
this.el = document.getElementById(elId);
if (!this.el) return;
this.numEl = this.el.querySelectorAll('.scroll-anim-21__count');
this.countTime = 1000;
this.countInterval = 50;
}
/**
* 初期化
*/
init(): void {
if (!this.el) return;
this.scrollHandler();
}
/**
* カウントアップ開始
*/
startCountUp() {
[...this.numEl].forEach(el => {
let count = el.dataset.count;
this.countUp(el, Number(count));
});
}
/**
* カウントアップ
* @param el カウントする要素
* @param count カウント数
*/
countUp(el: HTMLElement, count: number) {
let currentNumber = 0;
let currentTime = 0;
const timer = setInterval(() => {
el.textContent = currentNumber.toString();
currentTime += this.countInterval;
currentNumber = Math.floor(count / this.countTime * currentTime);
if(currentTime === this.countTime){
clearInterval(timer);
el.textContent = count.toString();
}
}, this.countInterval);
}
/**
* スクロール連動のイベント設定
*/
scrollHandler(): void {
const options = {
// @ts-ignore
root: null,
rootMargin: '-30% 0px',
threshold: 0
}
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.startCountUp();
observer.disconnect();
}
});
}, options);
observer.observe(this.el);
}
}
No notes defined.