JS의 .animate() 속성을 이용해서 클릭&드래그로 좌우로 이동하는 DOM을 만들건데,
1. 자식요소들을 감싸고 있는 부모만 움직임
2. 자식요소엔 클릭이벤트만 적용 (클릭시 크기가 줄어들었다/원래크기로 돌아옴)
3. 부모가 움직이고 난 후에도 자식 위에 마우스 커서가 있을때 원래는 클릭이벤트로 간주되지만, 이를 원치않음. 따라서 부모가 움직였다면 마우스 커서가 자식 위에 있더라도 클릭이벤트를 처리하지 않음.
4. 부모를 움직일때도 일정 거리 이상 마우스 커서를 움직이지 않으면, 부모도 움직이지 않게 할 것임. (이렇게 하지 않으면 아주 조그만 움직임에도 부모는 움찔거리며 계속 움직임)
See the Pen Untitled by Oh Ikmyeong (@dpffpself) on CodePen.
HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mousedown, click</title>
<link rel="stylesheet" href="./style.css">
<script src="./main.js" type="module"></script>
</head>
<body>
<ul id="list">
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
<li class="item">4</li>
<li class="item">5</li>
<li class="item">6</li>
<li class="item">7</li>
<li class="item">8</li>
<li class="item">9</li>
<li class="item">10</li>
</ul>
</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
|
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
li{list-style-type:none;}
body{
overflow:hidden;
display:flex;flex-flow:column nowrap;
justify-content:center; align-items:flex-start;
min-height:100vh;
background:#eee;
}
#list{
display:flex;flex-flow:row nowrap;
justify-content:flex-start; align-items:center;
gap:20px;
position:relative;
padding:30px; margin:0 30px;
background:#ccc;
cursor:move;
}
.item{
flex:none;
display:flex;
justify-content:center; align-items:center;
position:relative;
width:max(15vw, 200px); aspect-ratio:16/9;
background:#fff;
border-radius:10px;
user-select:none;
cursor:pointer;
font-size:5vmin;
transition:transform .3s;
}
.item.on{
transform:scale(0.5);
}
|
cs |
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
|
const $list = document.getElementById('list');
const $$item = document.querySelectorAll('.item');
const POS = {
x : 0,
wid : null,
}
const REMEMBER = {
down : 0,
up : 0
}
const LIMIT_MOVE = 50;
function on_mouse_down(e){
// console.log('0.mouse down');
const {clientX} = e;
const {left,width} = $list.getBoundingClientRect();
REMEMBER.down = clientX;
POS.x = clientX - left;
POS.wid = width;
window.addEventListener('mousemove', on_mouse_move);
window.addEventListener('mouseup', on_mouse_up, {once:true});
}//on_mouse_down
function on_mouse_move(e){
// console.log('1.mouse move');
const {clientX} = e;
if(Math.abs(REMEMBER.down - clientX) < LIMIT_MOVE) return;
const newX = clientX - POS.x;
const finalX = (newX < -1 * POS.wid) ? -1 * POS.wid + LIMIT_MOVE : (newX >= window.innerWidth ? window.innerWidth - LIMIT_MOVE : newX);
$list.animate([{
transform : `translateX(${finalX}px)`
}],{
duration : 1000,
easing : "ease-in",
fill : "both"
});
}//on_mouse_move
function on_mouse_up(e){
// console.log('2.mouse up');
REMEMBER.up = e.clientX;
window.removeEventListener('mousemove', on_mouse_move);
$list.addEventListener('mousedown',on_mouse_down, {once:true});
}//on_mouse_up
function on_click(e){
const flag = Math.abs(REMEMBER.up - REMEMBER.down) < LIMIT_MOVE ? true : false;
if(!flag) return;
console.log('📍 item click');
e.currentTarget.classList.toggle('on');
}//on_click
$list.addEventListener('mousedown',on_mouse_down, {once:true});
$$item.forEach($item =>{
$item.addEventListener('click', on_click);
});
|
cs |
굳이 click 이벤트를 아이템마다 걸지 않고, mouse_up 쪽에 if 문으로 e.target == 아이템 이라면 처리해도 좋다.
이는 취향차...
'CSS&JS > ⚡Thinkers' 카테고리의 다른 글
[JS,Canvas] 캔버스로 화살표 선 만들기 (0) | 2023.11.29 |
---|---|
[CSS/JS]vanilla JS로 핸들러 2개인 range input 구현하기(기본) (2) | 2023.10.11 |
[JS] .animate() 또는 setTimeout과 Promise로 marquee 효과 만들기 (0) | 2023.07.13 |
[JS][Canvas] 캔버스로 파이그래프 그리기 (0) | 2023.04.29 |
[JS]바닐라 자바스크립트로 slick slider 간단히 구현해보기 (0) | 2023.01.20 |