220428
const moveBtn = document.createElement('div');
moveBtn.className = 'arrow';
const prevA = document.createElement('a');
const nextA = document.createElement('a');
prevA.className = 'prev';
nextA.className = 'next';
prevA.textContent = '이전';
nextA.textContent = '다음';
prevA.href = "";
nextA.href = "";
moveBtn.appendChild(prevA);
moveBtn.appendChild(nextA);
kindWrap.appendChild(moveBtn);
const moveBtn = document.createElement('div');
moveBtn.className = 'arrow';
moveBtn.innerHTML = `
<a href="" class="prev">이전</a>
<a href="" class="next">다음</a>
`;
kindWrap.appendChild(moveBtn);
사용자가 어떤 태그 안에서 이 슬라이더를 쓸지 모르니까
ul 태그, img 태그만 있어도 알아서 찾아서 사용자가 쓰고 싶은 태그 안에 넣어줄 수 있게 하자.
<ul class="slider">
<li><img src="https://via.placeholder.com/800x200.png?text=1" alt=""></li>
<li><img src="https://via.placeholder.com/800x200.png?text=2" alt=""></li>
<li><img src="https://via.placeholder.com/800x200.png?text=3" alt=""></li>
</ul>
그니까 이 부분만 가지고서도 자동으로 부모요소인 kindWrap, kindSlider 태그들을 만들어줄 수 있도록.
// const kindWrap = document.querySelector('.kind_wrap');
// const slider = kindWrap.querySelector('.slider');
const slider = document.querySelector('.slider');
그래서 slider(ul 태그의 클래스명)를 kindWrap이 아니라 document에서 찾도록 하자.
그래서 slider의 부모를 찾아서 그 부모 안에다가 kind_wrap 만들고, kind_wrap에다가 kind_slider를 만드는거야.
const slider = document.querySelector('.slider');
const kindWrap = document.createElement('div');
kindWrap.className = 'kind_wrap';
slider.parentNode.insertBefore(kindWrap, slider);
const kindSlider = document.createElement('div');
kindSlider.className = 'kind_slider';
kindWrap.appendChild(kindSlider);
kindSlider.appendChild(slider);
그래서 kindWrap을 html에 div 태그로 만들어주고, 그것을 slider의 부모 노드를 찾아서(parentNode) 자식으로 넣어준다.
* insertBefore(넣어줄 아이, 넣어줄 아이의 뒤에 올 애)
kindSlider도 html에 div 태그로 만들어주고, 그것을 아까 만들어준 kindWrap의 자식으로 넣어준다.
kindSlider까지 만들었으니 그것의 자식으로 slider을 넣어준다.
하여간 이제 잘 동작하는 슬라이더를 만들었다.
이제 html, css, js 파일을 모두 나누어 잘 정리했다.
<!DOCTYPE html>
<html lang="ko">
<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>Document</title>
<link rel="stylesheet" href="./k-slider.css">
<script src="./k-slider.js"></script>
</head>
<body>
<ul class="slider">
<li><img src="https://via.placeholder.com/800x200.png?text=1" alt=""></li>
<li><img src="https://via.placeholder.com/800x200.png?text=2" alt=""></li>
<li><img src="https://via.placeholder.com/800x200.png?text=3" alt=""></li>
</ul>
<script>
window.onload = function() {
kSlider();
}
</script>
</body>
</html>
* {margin:0; padding:0}
li {list-style: none;}
.kind_wrap {border:2px solid black; width:100%; max-width:800px; margin:0 auto; position: relative;}
.kind_wrap > .kind_slider {overflow: hidden;}
.kind_wrap > .kind_slider .slider {
position: relative;
}
.kind_wrap > .kind_slider .slider li {float:left}
.kind_wrap > .kind_slider img {vertical-align: top;}
.kind_wrap .arrow > a.prev {position: absolute; left:-50px; top:100px}
.kind_wrap .arrow > a.next {position: absolute; right:-50px; top:100px;}
function kSlider() {
// 노드 준비
const slider = document.querySelector('.slider');
const kindWrap = document.createElement('div');
kindWrap.className = 'kind_wrap';
slider.parentNode.insertBefore(kindWrap, slider);
const kindSlider = document.createElement('div');
kindSlider.className = 'kind_slider';
kindWrap.appendChild(kindSlider);
kindSlider.appendChild(slider);
const sliderLis = slider.querySelectorAll('li');
const cloneF = sliderLis[0].cloneNode(true); //First의 clone
const cloneL = sliderLis[sliderLis.length-1].cloneNode(true); //Last의 clone
slider.insertBefore(cloneL, sliderLis[0]);
slider.appendChild(cloneF);
const moveBtn = document.createElement('div');
moveBtn.className = 'arrow';
moveBtn.innerHTML = `
<a href="" class="prev">이전</a>
<a href="" class="next">다음</a>
`;
kindWrap.appendChild(moveBtn);
//주요 변수 초기화
let moveDist = 0;
let currentNum = 1;
const speedTime = 500;
//ul 넓이 계산해주기
//이 값을 css로 전달해주어야함
//.kind_wrap > .kind_slider 여기로
const sliderCloneLis = document.querySelectorAll('li');
const liWidth = sliderLis[0].clientWidth;
const sliderWidth = liWidth * sliderCloneLis.length;
slider.style.width = `${sliderWidth}px`; //sliderWidth + 'px' 와 같습니다.
slider.style.width = `${sliderWidth}px`
moveDist = -liWidth;
slider.style.left = `${-liWidth}px`;
//click listner 만들기
moveBtn.addEventListener('click', moveSlide);
function moveSlide(event) {
event.preventDefault();
console.log(event.target.className);
let clickclass = event.target.className; //class 이름(prev, next)
//이전
if (clickclass === 'prev') {
move(1);
if (currentNum === 0) {
setTimeout(() => {
slider.style.transition = 'none';
currentNum = sliderCloneLis.length-2;
moveDist = -liWidth * currentNum;
slider.style.left = `${-liWidth * currentNum}px`;
}, speedTime)
}
}
//다음
else {
move(-1);
if (currentNum === (sliderCloneLis.length-1)) {
setTimeout(() => {
slider.style.transition = 'none';
moveDist = -liWidth;
slider.style.left = `${-liWidth}px`;
currentNum = 1;
}, speedTime)
}
}
console.log(moveDist, currentNum);
}
function move(direction) {
moveDist += liWidth * direction;
currentNum += direction * (-1);
slider.style.left = `${moveDist}px`;
slider.style.transition = `all ${speedTime}ms ease`;
}
}
slider 말고 다른 이름 쓰고 싶을 수도 있으니까...
js에 파라미터 target. slider를 target으로
css의 slider를 ul로
speedtime을 함수에서 옵션값으로 줄 수 있게 하자.
ul과 li에 자유도를 주자.
css에서 원래 ul -> k_list, li -> k_item 이라는 클래스 네임 준다.
slider.classList.add('k_list');
slider에 클래스 네임을 하나 더 준다.
하나 더 추가하는거라 className 말고 classList로 준다.
slider는 주인공이니까 slider의 자식들인 item들을 찾을 수 있다.
const sliderLis = slider.children;
for(let i=0; i<sliderLis.length; i++) {
sliderLis[i].className = 'k_item';
}
sliderLis들을 slider의 자식을 할당해준다.
그럼 이미지 감싸고 있는 태그, slider의 자식이 잡힌다.
그리고 걔네들한테 모두 클래스네임으로 k_item을 준다.
const sliderCloneitems = document.querySelectorAll('.k_item');
밑에 클론 만들 때 썼던 'li' 도 'k_item'으로 잊지 말고 잘 바꿔준다.
그러면 ul과 li 태그도 어떤 태그가 와도 잘 작동할 수 있다!
그리고 sliderLis나 sliderCloneLis 같은 변수명들을 바꿔주자. 이제 우리는 li 쓰지 않으니까.
sliderLis -> sliderItems
sliderCloneLis -> sliderCloneItems
* 같은 단어를 찾을 때 그 단어를 드래그 해놓고 ctrl+f2 를 누르면 그 단어들에게 멀티커서 된다.
이제 onload()가 불편하다...
사진 3장만을 위해 모든 문서 페이지가 로드 됐는지 기다려야 하고
사용자가 함수에 클래스 네임, 옵션값만 넣으면 되게 하고 싶다.
js 파일에서 모든 코드를 innerName()이라는 함수를 새로 만들고, 그 위에 이미지 로드가 되었는지 확인하고 innerName()을 실행하도록 하자.
//이미지 로드가 된 것만 확인해서 innerName() 실행하기
const toBeLoaded = document.querySelectorAll(`${target} img`);
let loadedImgs = 0;
toBeLoaded.forEach((item) => {
item.onload = () => {
loadedImgs++;
if (loadedImgs === toBeLoaded.length){
innerName(target, option);
}
}
})
innerName() 에 파라미터도 잊지 말고 넣어주자.
classList와 className
className
특정 엘리먼트의 클래스 속성의 값을 가져오거나 설정할 수 있다.
classList
엘리먼트의 클래스 속성의 컬렉션인 활성 DOMTokenList를 반환하는 읽기 전용 프로퍼티이다.
특정 엘리먼트의 클래스 속성을 모아놓은 것이다.
classList는 하나씩 빼고 넣을 때 좋다.
className은 문자열로 한번에 넣을 때 좋다.