코드펜 Jon Kanter 님의 Handy Tally Counter 예제를 보고 원리를 내 방식대로 재구현해보았다.
차이점은 원본은 열마다 0~9까지 DOM이 존재하고, 이걸 9번 위로 올리는 방식이면,
나는 그냥 열마다 now, prev 2개의 DOM만 존재하고, setTimeout과 animationend를 이용하여 내용을 갈아치울거다.
그리고 col의 갯수가 몇개나 늘어나든 상관없이 짜볼거다 (0~999도 되고 0~99999도 되고)
데모 페이지 : https://ohikmyeong.github.io/code-pen-copy/Hand-Tally-Counter/mine/
See the Pen Counter by Oh Ikmyeong (@dpffpself) on CodePen.
HMTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Handy Tally Counter-Copy</title>
<link rel="stylesheet" href="./style.css">
<script src="./main.js" type="module"></script>
</head>
<body>
<p>
<a href="https://codepen.io/jkantner/pen/ZEQYKON" target="_blank">handy tally counter</a>
</p>
<section id="wrap-counter">
<article id="counter">
<div class="counter-col">
<span class="now">0</span>
<span class="next">1</span>
</div>
<div class="counter-col">
<span class="now">0</span>
<span class="next">1</span>
</div>
<div class="counter-col">
<span class="now">0</span>
<span class="next">1</span>
</div>
<div class="counter-col">
<span class="now">0</span>
<span class="next">1</span>
</div>
</article>
<button id="btn-one">1개씩</button>
<button id="btn-all">전부 맞추기</button>
</section><!-- wrap-counter -->
</body>
</html>
|
cs |
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
body{
display:flex; flex-flow:column nowrap;
justify-content:center; align-items:center;
gap:20px;
min-height:100vh;
text-align:center;
}
#wrap-counter{
display:flex;flex-flow:column nowrap;
justify-content:center;
gap:10px;
position:relative;
padding:10px;
background:#eee;
}
#counter{
--wid-col:40px;
display:flex;
justify-content:space-between; align-items:flex-start;
gap:10px;
position:relative; overflow:hidden;
height:var(--wid-col);
margin-bottom:var(--wid-col);
background:black;
border:1px solid black;
}
.counter-col{
position:relative;
width:var(--wid-col);
background:linear-gradient(to bottom, #888, #333,#888, #333,#888);
font-size:20px; font-weight:bold; color:#fff;
}
.counter-col.on{
animation:col-up .1s linear both;
}
.counter-col span{
display:block;
width:100%; aspect-ratio:1/1;
line-height:var(--wid-col);
}
button{position:relative;padding:.5em 2em;}
@keyframes col-up {
from{transform:translateY(0);}
to{transform:translateY(-50%);}
}
|
cs |
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
class HandyCounter {
constructor() {
this.COUNT = 0;
this.$counter = document.getElementById('counter');
this.MAXCOUNT = '';
}//constructor
/** initiate counter */
init() {
for(let i=0; i<this.get_now_all().length; i++) this.MAXCOUNT += '9';
this.MAXCOUNT = Number(this.MAXCOUNT);
const $btnOne = document.getElementById('btn-one');
const $btnAll = document.getElementById('btn-all');
$btnOne.addEventListener('click', this.on_click_one);
$btnAll.addEventListener('click', this.on_click_all);
}//init
/**
* $counter의 now DOM들을 모두 반환
* @returns {DOM} .now
*/
get_now_all() {
return Array.from(this.$counter.querySelectorAll('.now'));
}//get_now_all
/**
* col을 이동시키고 숫자를 바꾼다
* @param {DOM}$now .now
* @param {Number}num
*/
move_col($now, num) {
const $col = $now.parentElement;
$col.classList.add('on');
$col.addEventListener('animationend', this.on_ani_end($now,num), { once: true });
}//move_col
/**
* 애니메이션 종료시 col을 원위치로 하고 now와 next 값을 바꿉니다
* @param {DOM}$now .now
* @param {Number}num
* */
on_ani_end = ($now, num)=>{
setTimeout(() => {
const $col = $now.parentElement;
const $next = $now.nextElementSibling;
const next = (Number(num) + 1) % 10;
$now.textContent = num;
$next.textContent = next;
const cnt = this.get_now_all().map($now => $now.textContent).join('');
this.COUNT = Number(cnt);
$col.classList.remove('on');
}, 100);
}//on_ani_end
/**
* 버튼 클릭 - 한개씩만 카운트 증가
*/
on_click_one = () => {
this.COUNT++;
if (this.COUNT > this.MAXCOUNT) this.COUNT = 0;
const $$now = this.get_now_all();
const numStr = String(this.COUNT).padStart($$now.length, "0");
for (let i = 0; i < $$now.length; i++) {
const $now = $$now[i];
const num = numStr[i];
if ($now.textContent == num) continue;
this.move_col($now, num);
}//for
}//on_click_one
/**
* 버튼 클릭 - 전부 맞추기
*/
on_click_all = () => {
const $$now = this.get_now_all();
const min = Math.min(...$$now.map($now => $now.textContent));
for (let i = 0; i < $$now.length; i++) {
const $now = $$now[i];
const num = Number($now.textContent);
if (num > min) continue;
this.move_col($now, (num + 1) % 10);
}//for
}//on_click_all
}//HandyCounter
const COUNTER = new HandyCounter();
COUNTER.init();
|
cs |
'CSS&JS > 👀Study and Copy' 카테고리의 다른 글
[CSS+JS]카운트다운 SVG 애니메이션 (2) | 2022.12.30 |
---|---|
[JS]Codepen의 이미지 픽셀화 작업 카피(pw:1234) (0) | 2022.12.22 |
[Online Tutorials]Glowing Box (0) | 2022.12.16 |
[Nomad Coders] 바닐라 JS로 그림판 만들기 - 2021ver (0) | 2022.08.26 |
WDS-Snake Game (0) | 2022.08.22 |