1.0인 이유는 아직 터치를 구현 안해서...
깃허브 https://github.com/OhIkmyeong/custom_slider
디즈니플러스나 농협라이블리 같은 메인페이지의 슬라이더들 보면
- 무한으로 좌우 스크롤링 됨
- 현재 화면에 포커스 된 애들은 scale이 1.0 나머지는 그보단 작음
- (n-1) n (n+1) 3개의 엘리먼트가 한 화면에 보임.
현재까지 구현한거
- 이전/다음버튼으로 무한스크롤링
- 드래그 까진 아니지만 마우스로 무한스크롤링(mousedown, mouseend)
- 자동재생 on/off
미흡한거
- 한계점에선 뚝뚝 끊겨서 부드러운 무한 스크롤링은 아님 ㅋㅋ ㅠ 에라이~~~
구현해야 할거
- 터치
- 자동재생 남은 시간 표시
어쨌든 에센셜은 있다구용?!
index.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
25
26
27
28
29
30
|
<!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>copying swiper</title>
<link rel="stylesheet" type="text/css" href="./slider/slider.css"/>
<script src="./main.js" type="module"></script>
</head>
<body>
<h1>짭 swiper</h1>
<ul class="swiper">
<li><div class="swiper-content">0</div></li>
<li><div class="swiper-content">1</div></li>
<li><div class="swiper-content">2</div></li>
<li><div class="swiper-content">3</div></li>
</ul>
<footer><a href="https://aosceno.tistory.com/" target="_blank">티스토리</a></footer>
<template>
<!-- swiper-wrap을 만들고 그 안에 swiper를 추가한다. -->
<!-- swiper-wrap 안에 추가해줍니다 -->
<button class="swiper-btn" data-btn="prev">이전</button>
<button class="swiper-btn" data-btn="next">다음</button>
</template>
</body>
</html>
|
cs |
slider.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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
li{list-style-type:none;}
html,body{overflow-x:hidden;}
.swiper-wrap{
outline:1px solid red;
position:relative; overflow:hidden;
width:100%; aspect-ratio:5/1.5;
margin:2rem auto;
background:#eee;}
.swiper-wrap .swiper{
display:flex; flex-flow:row nowrap;
justify-content:flex-start; align-items:center;
position:relative;
height:100%;
transition:transform .5s;
cursor:grab;
}
.swiper-wrap .swiper li{
flex:none;
position:relative;
width:calc(100% - 400px); height:100%;
border:2px solid red;}
.swiper-wrap .swiper li .swiper-content{
display:flex;
justify-content:center;align-items:center;
position:relative;
width:100%;height:100%;
background:#333;
text-align:center; font-size:10vw; color:#fff;
transform:scale(.8);
transition:transform .5s;
pointer-events:none; user-select:none;
}
.swiper-wrap .swiper li.on > div{transform:scale(1);}
/* 버튼 */
.swiper-wrap .swiper-btn{
position:absolute;
top:100%; left:50%;
padding:1rem;
cursor:pointer;}
.swiper-wrap .swiper-btn[data-btn="prev"]{
transform:translate(-50%,-100%);
}
.swiper-wrap .swiper-btn[data-btn="next"]{
transform:translate(50%,-100%);
}
/* 자동재생 버튼 */
.btn_timer{
position:absolute;
right:0; bottom:0;
padding:1rem;
}
|
cs |
main.js
1
2
3
4
5
|
import { Swiper } from "./slider/slider.js";
const $swiper = document.getElementsByClassName('swiper')[0];
new Swiper($swiper);
|
cs |
slider.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
|
import { MakeSlider } from "./makeSlider.js";
import { PosSlider } from "./positionSlider.js";
import { Timer } from "./timeSlider.js";
export class Swiper{
constructor($elem){
this.MAKE = new MakeSlider(this);
this.POS = new PosSlider(this);
this.TIMER = new Timer(this);
this.$wrap = undefined;
this.$elem = $elem;
this.flag = true;
this.init();
}//constructor
init(){
this.MAKE.init();
this.POS.init();
this.add_event();
this.TIMER.init();
}//init
add_event(){
this.$wrap.addEventListener('click',this.on_btn);
this.$wrap.addEventListener('mousedown',this.POS.mousePos_start);
this.$wrap.addEventListener('mouseup',this.POS.mousePos_end);
}//add_event
on_btn = (e) => {
if(!this.flag){return;}
const direction = e.target.dataset.btn;
if(!direction){return;}
this.flag = false;
this.TIMER.clear_timer();
switch(direction){
case "prev" :
this.POS.curr--;
break;
case "next" :
this.POS.curr++;
break;
}//switch
this.POS.move_to();
}//on_btn;
}//class-Swiper
|
cs |
makeSlider.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
|
export class MakeSlider{
constructor(SLIDER){
this.SLIDER = SLIDER;
}
/* 총괄 */
init(){
this.put_in_to_wrap();
this.add_li();
this.make_btn();
}//init
/* wrap 만들어서 그 안으로 옮긴다 */
put_in_to_wrap(){
const $elem = this.SLIDER.$elem;
const $parent = $elem.parentElement || document.body;
const $wrap = document.createElement('DIV');
$wrap.classList.add('swiper-wrap');
$parent.insertBefore($wrap,$elem);
$wrap.appendChild($elem);
this.SLIDER.$wrap = $wrap;
}//put_in_to_wrap
/* 버튼 추가 */
make_btn(){
const $wrap = this.SLIDER.$wrap;
const $prev = document.createElement('BUTTON');
const $next = document.createElement('BUTTON');
$prev.classList.add('swiper-btn');
$next.classList.add('swiper-btn');
$prev.dataset.btn = "prev";
$next.dataset.btn = "next";
$prev.textContent = '이전';
$next.textContent = '다음';
$wrap.appendChild($prev);
$wrap.appendChild($next);
}//make_btn
/* 0,1과 n과 n-1을 앞 뒤로 추가해줘야함 */
add_li(){
const $elem = this.SLIDER.$elem;
const $$li = $elem.children;
const $first = $$li[0];
const $0 = $first.cloneNode(true);
const $1 = $$li[1].cloneNode(true);
const $n_1 = $$li[$$li.length - 2].cloneNode(true);
const $n = $$li[$$li.length - 1].cloneNode(true);
const $frag_next = document.createDocumentFragment();
$frag_next.appendChild($0);
$frag_next.appendChild($1);
const $frag_before = document.createDocumentFragment();
$frag_before.appendChild($n_1);
$frag_before.appendChild($n);
$elem.insertBefore($frag_before, $elem.firstChild);
$elem.appendChild($frag_next);
}//add_li
}//class-MakeSlider
|
cs |
positionSlider.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
export class PosSlider{
constructor(SLIDER){
this.SLIDER = SLIDER;
this.WID = {
win : window.innerWidth,
li : undefined};
this.GAP = undefined;
this.limit = {first : undefined, last:undefined};
this.mousePos = {start:undefined, end:undefined};
this.curr = 2;
this.transition = `transform .5s`;
this.time = 2000;
this.timer = undefined;
}//constructor
init(){
this.add_resize_event();
this.set_size();
this.set_limit();
this.move_to(this.curr);
this.SLIDER.TIMER.run_timer();
}//init
add_resize_event(){
window.addEventListener('resize',()=>{
this.set_size();
this.set_limit();
this.move_to(this.curr);
});
}//add_resize_event
set_size(){
this.WID.win = parseInt(window.innerWidth);
this.WID.li = this.WID.win - 400;
this.GAP = (this.WID.win - this.WID.li) / 2;
}//set_size
set_limit(){
const len = this.SLIDER.$elem.children.length - 2;
this.limit.first = (this.WID.li * -1) + this.GAP;
this.limit.last = (this.WID.li * -1 * len) + this.GAP;
}//set_limit
async move_to(){
const $elem = this.SLIDER.$elem;
const movement = (this.WID.li * -1 * this.curr) + this.GAP;
await this.move(movement);
if(this.curr < 2){
console.log('끝으로 변경해야돼');
this.curr = $elem.children.length - 3;
$elem.children[this.curr].classList.add('on');
await this.remove_transition_and_move();
}else if(this.curr >= $elem.children.length - 2){
console.log('시작으로 변경해야돼');
this.curr = 2;
$elem.children[this.curr].classList.add('on');
await this.remove_transition_and_move();
}else{
this.add_on();
}//if
this.SLIDER.flag = true;
}//move_to
move(movement){
const $elem = this.SLIDER.$elem;
$elem.style.transform = `translateX(${movement}px)`;
return new Promise((res)=>{
setTimeout(()=>{
res('');
},500);
});
}//move
add_on(){
const $$li = this.SLIDER.$elem.children;
const curr = $$li[this.curr];
curr.classList.add('on');
for(let $li of $$li){
if($li == curr){continue;}
$li.classList.remove('on');
}
}//add_on
async remove_transition_and_move(){
await this.remove_transition();
this.restore_transition();
}//remove_transition_and_move
remove_transition(){
this.SLIDER.$elem.style.transition = 'none';
this.move_to(this.curr);
return new Promise((res)=>{
setTimeout(()=>{
res();
},100);
});
}//remove_transition
restore_transition(){
this.SLIDER.$elem.style.transition = this.transition;
}//restore_transition
mousePos_start = (e)=>{
this.mousePos.start = e.clientX;
this.SLIDER.$elem.style.cursor = 'grabbing';
}//mousePos_start
mousePos_end = (e)=>{
this.flag = false;
this.SLIDER.$elem.style.cursor = 'grab';
this.SLIDER.TIMER.clear_timer();
this.mousePos.end = e.clientX;
const {start, end} = this.mousePos;
const gap = end - start;
if(gap > 0){
this.curr--;
}else if(gap < 0){
this.curr++;
}
this.move_to();
}//mousePos_end
}//class-PosSlider
|
cs |
timeSlider.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
|
export class Timer{
constructor(SLIDER){
this.SLIDER = SLIDER;
this.time = 2000;
this.timer = undefined;
this.$btn = undefined;
}//constructor
init(){
this.add_timer();
}//init
/* 자동재생 버튼 달기 */
add_timer(){
const $wrap = this.SLIDER.$wrap;
const $btn_timer = document.createElement('BUTTON');
$btn_timer.classList.add('btn_timer');
$btn_timer.textContent = '자동 재생 off';
$btn_timer.dataset.auto = "on";
$wrap.appendChild($btn_timer);
this.$btn = $btn_timer;
}//add_timer
run_timer(){
this.SLIDER.POS.curr++;
this.SLIDER.POS.move_to();
this.timer = setTimeout(()=>{this.run_timer();},this.time);
}//run_timer
clear_timer(){
clearTimeout(this.timer);
this.toggle_btn();
}//clear_timer
toggle_btn(){
const auto = this.$btn.dataset.auto;
this.$btn.textContent = `자동 재생 ${auto}`;
const change = auto == "on" ? "off" : "on";
this.$btn.dataset.auto = change;
if(change == "on"){this.run_timer();}
}//toggle_btn
}//class-Timer
|
cs |
'CSS&JS > ⚡Thinkers' 카테고리의 다른 글
[JS] thead의 th를 누르면 그 항목에 맞춰 table sort 되게 하기 (0) | 2022.03.31 |
---|---|
promise의 finally를 이용한 로딩화면 (0) | 2022.03.02 |
커스텀 셀렉트 박스 만들기(2) - HTML DOM에는 select만 작성하고 vaniila JS로 알아서 DIV 생성 (0) | 2022.02.08 |
[JS] 바닐라 자바스크립트로 간단한 계산기 만들어보기(2) (0) | 2022.01.03 |
[JS] 바닐라 자바스크립트로 간단한 계산기 만들어보기 (0) | 2022.01.03 |