강의를 보며 혼자 정리하는 느낌이라.. 조금 조잡하고 설명이 정확하지 않을 수 있습니다
HTML,CSS는 강의자료로 받았고, 기능만 구현했습니다.
완성본
기능 설명
- Previous , Next 버튼 슬라이드
- Indicator를 사용해, 현재 슬라이드가 몇 번째인지 알려주고, Indicator 를 클릭 시, 클릭한 인덱스의 슬라이드로 갈 수 있게 함.
- setInterval 함수와 clearInterval 함수를 활용해, 자동으로 슬라이드가 넘어가고 오토 슬라이드를 정지할 수 있는 기능
HTML 과 CSS
강의 자료이기때문에, 참고용으로 보시라고 캡쳐본으로 올립니다
javascript 초기 작업
스크립트는 ES6 클래스 문법을 사용했습니다. ( 저도 아직 ES6 문법에 익숙치 않아서 기능 구현에 중점을 맞춰서 설명합니다 )
슬라이더 기능에서 사용 할 변수를 지정해줍니다.
#currentPosition = 0; // 현재 슬라이드 순서
#sliderNumber = 0; // 총 슬라이드의 length
#slideWidth = 0; // 슬라이드 한개의 넓이
#intervalId; // setInterval 중지를 위해서 함수를 넣어놓을 공간
#autoPlay = true; // setInterval이 실행중인지 알기 위한 변수
사용 할 Element 들 찾아주기
sliderWrapEl; // 슬라이더의 전체 요소를 묶고 있는 아이
sliderListEl; // 슬라이더의 컨텐츠들을 (즉 슬라이드 이미지들 )을 묶고 있는 아이
nextBtnEl; // 다음 버튼
previousBtnEl; // 이전 버튼
indicatorWrapEl; // 인디케이터를 묶고 있는 부모 요소
controlWrapEl; // Autoplay를 조절할 수 있게하는 버튼을 묶어놓은 부모 요소
assignElement() {
this.sliderWrapEl = document.getElementById('slider-wrap');
this.sliderListEl = this.sliderWrapEl.querySelector('#slider');
this.nextBtnEl = this.sliderWrapEl.querySelector('#next');
this.previousBtnEl = this.sliderWrapEl.querySelector('#previous');
this.indicatorWrapEl = this.sliderWrapEl.querySelector('#indicator-wrap');
this.controlWrapEl = this.sliderWrapEl.querySelector('#control-wrap');
}
sliderWrapEl 을 통해서 querySelector 로 Element 를 찾아주는 이유
- Document 부터 요소들을 찾게하지 않고, 이 요소들을 전체적으로 묶어주는 아이부터 찾도록 해서 비용 절감을 할 수 있도록 하기 위해서 (라고합니다)
초기화 작업을 해줍니다.
this에 바인딩되어 있는 인스턴스에 프로퍼티나 메서드를 추가하고 생성자 함수가 인수로 전달받은 초기값을 인스턴스 프로퍼티에 할당하여 초기화하거나 고정값을 할당하기위해 작업한 것 같아요
- 슬라이드의 총 갯수를 알아내는 함수
initSliderNumber() {
this.#sliderNumber = this.sliderListEl.querySelectorAll('li').length;
} // 슬라이드의 개수를 알기 위한 초기함수
- 슬라이드 한 개의 넓이를 알아내는 함수
initSlideWidth() {
this.#slideWidth = this.sliderWrapEl.clientWidth;
} // 슬라이드 컨텐츠의 한개 넓이를 알기 위한 함수
- 슬라이드의 전체 넓이를 동적으로 할당해주는 함수
initSliderListWidth() {
this.sliderListEl.style.width = `${
this.#sliderNumber * this.#slideWidth
}px`;
} // 슬라이드 컨텐츠의 개수와 슬라이드 한 개의 넓이를 곱해서, 전체 넓이를 동적으로 할당해주기 위한 함수
- addEventListener 함수를 사용하는 코드 묶어놓기
addEvent() {추후에 들어갈 addEventListener 함수}
- constructor 에 클래스 필드를 선언하고 초기화 해주기
constructor() {
this.assignElement();
this.initSliderNumber();
this.initSlideWidth();
this.initSliderListWidth();
this.addEvent();
}
constructor 에 짧게.. 알아봤습니다
- 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메서드
- constructor 는 클래스 안에 한 개만 존재 가능
- 클래스 필드의 선언과 초기화는 반드시 constructor 내부에서 실시
- constructor 내부에서 선언한 클래스 필드는 클래스가 생성 할 인스턴스에 바인딩 된다
기본 슬라이드 구현하기
next 버튼과, previous 버튼에게 이벤트 리스너를 준다
addEvent() {
this.nextBtnEl.addEventListener('click', this.moveToRight.bind(this));
this.previousBtnEl.addEventListener('click', this.moveToLeft.bind(this));
}
콜백 함수를 사용했기 때문에, bind 메소드를 활용해, this 를 바인딩 해준다.
moveToRight ()
moveToRight() {
this.#currentPosition += 1;
if (this.#currentPosition === this.#sliderNumber) {
this.#currentPosition = 0;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
}
1. 버튼을 클릭 시, currentPosition 의 값이 +1 될 수 있도록 했음 (오른쪽으로 가려면, left 값이 늘어나야하기 때문에)
2. 현재 슬라이드 순서가 슬라이더의 마지막 순서의 인덱스와 같을 시, 첫 번째 슬라이드로 이동 될 수 있게 if 문 사용
3. 버튼을 누를 때마다 옆으로 이동되는 모습을 구현하기 위해서 style.left를 사용
4. left 이동하는 위치는, 현재 슬라이드 순서값과, 슬라이드 한개의 넓이를 곱해서 구현
moveToLeft ()
moveToLeft() {
this.#currentPosition -= 1;
if (this.#currentPosition === -1) {
this.#currentPosition = this.#sliderNumber - 1;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
}
1. 버튼을 클릭 시, currentPosition 의 값이 -1 될 수 있도록 했음 (왼쪽으로 가려면, left 값이 줄어들어야하기 때문에)
2. 현재 슬라이드 순서가 슬라이더의 첫번째 순서(index = 0)보다 적을 경우 , 마지막 순서 슬라이드로 이동 될 수 있게 if 문 사용
3. 버튼을 누를 때마다 옆으로 이동되는 모습을 구현하기 위해서 style.left를 사용
4. left 이동하는 위치는, 현재 슬라이드 순서값과, 슬라이드 한개의 넓이를 곱해서 구현
인디케이터(Indicator) 를 활용한 슬라이더 구현하기
인디케이터를 동적으로 생성할 수 있게 한다 ( 슬라이드 개수에 맞춰서 생성 될 수 있게 )
createIndicator() {
const docFragment = document.createDocumentFragment();
for (let i = 0; i < this.#sliderNumber; i += 1) {
const li = document.createElement('li');
li.dataset.index = i;
docFragment.appendChild(li);
}
this.indicatorWrapEl.querySelector('ul').appendChild(docFragment);
}
constructor() {
this.assignElement();
this.initSliderNumber();
this.initSlideWidth();
this.initSliderListWidth();
this.addEvent();
this.createIndicator(); // 추가해주기
}
1. 슬라이드 개수만큼 인디케이터를 생성해주기 위해서 for 문을 사용해준다.
2. 인디케이터는 ul 안에 li 로 생성해준다.
3. li 안에 data-index 를 만들어주어, index 를 알 수 있도록 한다.
4. indicatortWrap (div) 안에 있는 ul 안에 li 를 생성해주기 위해서 appendChild 를 사용해주도록 한다.
5. constructor 안에 함수를 추가해준다.
* createDocumentFragment()
다른 노드를 담는 임시 컨테이너 역할을 하는 특수노드이다. 하지만 Element처럼, appendChild()와 insertBefore() 등으로 조작할 수 있는 자손 객체를 가질 수 있다.
인디케이터에서 현재 슬라이드를 알게 해주는 함수
setIndicator() {
this.indicatorWrapEl.querySelector('li.active')?.classList.remove('active');
this.indicatorWrapEl
.querySelector(`ul li:nth-child(${this.#currentPosition + 1})`)
.classList.add('active');
}
constructor() {
this.assignElement();
this.initSliderNumber();
this.initSlideWidth();
this.initSliderListWidth();
this.addEvent();
this.createIndicator();
this.setIndicator();
}
1. 만들어놓은 li (인디케이터 요소) 중 "active" 라는 클래스를 갖고 있는 요소에게 클래스를 지워주는 작업을 해준다.
2. li 태그에서 현재 슬라이드 순서에 맞게 "active" 클래스를 추가해준다
- +1 를 해준 이유는 nth-child 는 0부터 시작하지 않고 1부터 시작하기 때문에, +1 를 추가해주어야함.
3. constructor 에 함수를 추가해준다.
moveToRight() {
this.#currentPosition += 1;
if (this.#currentPosition === this.#sliderNumber) {
this.#currentPosition = 0;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
this.setIndicator(); // 추가
}
moveToLeft() {
this.#currentPosition -= 1;
if (this.#currentPosition === -1) {
this.#currentPosition = this.#sliderNumber - 1;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
this.setIndicator(); // 추가
}
1. moveToRight 와 moveToLeft 함수가 실행 될 때도, 인디케이터가 실행될 수 있도록 setIndicator() 함수를 호출한다.
인디케이터를 클릭하면 슬라이드가 이동하는 함수
addEvent() {
this.nextBtnEl.addEventListener('click', this.moveToRight.bind(this));
this.previousBtnEl.addEventListener('click', this.moveToLeft.bind(this));
this.indicatorWrapEl.addEventListener(
'click',
this.onClickIndicator.bind(this),
); // 추가 된 함수
}
onClickIndicator(event) {
const indexPosition = parseInt(event.target.dataset.index, 10);
if (Number.isInteger(indexPosition)) {
this.#currentPosition = indexPosition;
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
this.setIndicator();
}
}
1. 인디케이터를 감싸고 있는 부모 요소에게 addEventListener 함수를 준다 (이벤트 버블링때문에)
2. indexPosition 이라는 변수에 만들어놓은 li 속성인 data-index를 숫자 타입으로 바꿔준다.
- 10을 넣은 이유는 10진법으로 만들어달라고 하는 것이라고 합니다.
3. indexPosition 이 정수라면, moveTo 함수와 같은 이벤트를 준다.
4. 바뀐 currentPosition 값을 인디케이터에도 적용해줘야하기 때문에 , setIndicator() 함수를 호출한다.
AutoPlay 슬라이더 구현하기
AutoPlay 기본 기능 구현하기
initAutoPlay() {
this.#intervalId = setInterval(this.moveToRight.bind(this), 3000);
}
constructor() {
this.assignElement();
this.initSliderNumber();
this.initSlideWidth();
this.initSliderListWidth();
this.addEvent();
this.createIndicator();
this.setIndicator();
this.initAutoPlay();
}
1. claerInterval() 를 사용하기 위해서 IntervalId 에 setInterval 함수를 구현해준다.
2. moveToRight 의 기능이 3초 간격으로 실행될 수 있도록 해준다.
- 이 함수 또한 콜백 함수이기 때문에 this 를 바인딩 해준다 (bind 메소드)
3. constructor 에 initAutoPlay() 를 추가해준다.
AutoPlay 실행, 정지 기능 구현하기 ( togglePlay )
addEvent() {
this.nextBtnEl.addEventListener('click', this.moveToRight.bind(this));
this.previousBtnEl.addEventListener('click', this.moveToLeft.bind(this));
this.indicatorWrapEl.addEventListener(
'click',
this.onClickIndicator.bind(this),
);
this.controlWrapEl.addEventListener('click', this.togglePlay.bind(this)); // 추가
}
togglePlay(event) {
if (event.target.dataset.status === 'play') {
this.#autoPlay = true;
this.controlWrapEl.classList.add('play');
this.controlWrapEl.classList.remove('pause');
this.initAutoPlay();
} else if (event.target.dataset.status === 'pause') {
this.#autoPlay = false;
this.controlWrapEl.classList.remove('play');
this.controlWrapEl.classList.add('pause');
clearInterval(this.#intervalId);
}
}
1. autoplay 의 버튼을 감싸고 있는 부모요소에게 addEventListener 함수를 적용
2. 버튼의 속성 중 data-status 를 활용해준다.
- play 일 경우는 만들어놓은 autoplay 변수를 true 로 만들어준다.
- 부모요소에게 "play" 라는 클래스를 추가해주고 "pause" 라는 클래스를 제거해준다. (현재 실행 상태를 알려주기 위해서)
- initAutoPlay () 함수를 호출 해, autoplay 가 실행될 수 있도록 한다.
- pause 일 경우는 만들어놓은 autoplay 변수를 false 로 만들어준다.
- 부모요소에게 "play" 라는 클래스를 제거하고, "pause" 라는 클래스를 추가해준다. (현재 실행 상태를 알려주기 위해서)
- clearInterval() 함수에 실행되고 있던 autoPlay setInterval 함수를 넣어, 실행을 멈추게 해준다.
AutoPlay 가 실행되는 중에 버튼 클릭 이벤트를 사용할 경우
moveToRight() {
this.#currentPosition += 1;
if (this.#currentPosition === this.#sliderNumber) {
this.#currentPosition = 0;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
if (this.#autoPlay) {
clearInterval(this.#intervalId);
this.#intervalId = setInterval(this.moveToRight.bind(this), 3000);
} // 추가
this.setIndicator();
}
moveToLeft() {
this.#currentPosition -= 1;
if (this.#currentPosition === -1) {
this.#currentPosition = this.#sliderNumber - 1;
}
this.sliderListEl.style.left = `-${
this.#slideWidth * this.#currentPosition
}px`;
if (this.#autoPlay) {
clearInterval(this.#intervalId);
this.#intervalId = setInterval(this.moveToRight.bind(this), 3000);
} // 추가
this.setIndicator();
}
1. autoPlay 라는 변수가 true 라면 (즉 play 중이라면), 버튼을 클릭 시 autoplay 를 중단하고 버튼 클릭 이벤트를 수행하게 함.
2. 버튼 클릭 이벤트가 종료된다면 다시 autoplay를 이어나가도록 함. (3초 뒤에 다시 이벤트 실행)
전체 기능 구현 코드
'Javascript > 응용프로젝트' 카테고리의 다른 글
자바스크립트로 BMI 계산기 구현하기 (0) | 2023.01.03 |
---|---|
자바스크립트로 Date-Picker 구현하기 (0) | 2023.01.03 |
[뉴스 타임즈] API 에러 발생시 UI 보여주기 (0) | 2022.10.24 |
[뉴스 타임즈] 반복된 코드 정리 (0) | 2022.10.24 |
[뉴스 타임즈] 키워드 검색 (0) | 2022.10.24 |