개요
[JS] 아코디언 라이브러리 - 1에서 기본적으로 만들었던 아코디언 라이브러리를 조금 더 업데이트 해보자.
작업 세부 사항
- 전체 아코디언 아이템들을 접거나, 펼칠 수 있는 매서드 제작
- 초기 셋팅시 className 및 초기 펼침 여부, 중복 펼침 허용 여부 설정
Accordion
class Accordion {
constructor(el, config) {
this.el = document.querySelector(el);
this.open = config?.open || false;
this.multi = config?.multi || false;
this.className = config?.className || 'active';
this.init();
}
init() {
this.items = [...this.el.querySelectorAll('.accordion_item')]
.map(item => new AccordionItem(item, this.el, this.className));
if(this.open) this.openAll();
if(!this.multi) this.el.addEventListener('accOpen', () => this.closeAll());
}
openNum(idx) { this.items[idx - 1].open(); }
closeNum(idx) { this.items[idx - 1].close(); }
openAll() { this.items.forEach(item => item.open()); }
closeAll() { this.items.forEach(item => item.active ? item.close() : null); }
}
const accrdion = new Accordion(".accordion", {
open: true,
multi: true,
className: "open"
})
하단과 같이 초기 설정을 입력해주기 위해 constructor에 config를 추가해주고,
.? 를 이용해서 값이 없는 경우 초기값을 지정해 주었다.
그 외 init 부분에서는 this.open이 true일 경우 this.openAll을 실행 시켜 주었고,
this.multi가 true일 경우 this.el에 커스텀 이벤트로 "accOpen"이 발생했을 때, this.closeAll()을 실행 시켜 주게 하였다.
openNum(idx), closeNum(idx)는 각각 this.items[idx - 1]을 open, close 시켜준다.
this.items 내부에 AccordionItem객체가 들어있으므로 AccordionItem객체 내부의 매서드인
open을 실행 시킬 수 있다.
idx - 1 을 해준 이유는 사용자가 0,1,2,3, .. 으로 시작하는 개념을 모를 수 있다고 생각하여,
직관적으로 이용할 수 있게 1을 넣으면 0, 2를 넣으면 1.. 이런식으로 작동 할 수 있게 처리 하였다.
openAll과 closeAll 또한 this.items를 이용하여 forEach문으로 모든 item을 open 시키거나, close 시켜주었다.
this.items에 AccordionItem 객체를 넣어두었기 때문에 편하게 작업이 가능했다.
또, AccordionItem 을 생성할때 this.el (아코디언 콘테이너) 그리고 className등을 추가로 전달해주었다.
AccordionItem
class AccordionItem {
constructor(el, parent, className) {
this.container = parent;
this.el = el;
this.className = className;
this.active = false;
this.title = this.el.querySelector('.accordion_title');
this.content = this.el.querySelector('.accordion_content');
this.style = this.el.style;
this.accOpen = new CustomEvent('accOpen');
this.init();
}
init() {
this.style.maxHeight = `${this.title.scrollHeight}px`;
this.style.overflow = 'hidden';
this.el.addEventListener('click', () => this.toggle());
if(this.el.classList.contains(this.className)) this.open();
}
open() {
this.container.dispatchEvent(this.accOpen);
this.active = true;
this.el.classList.add(this.className);
this.style.maxHeight = `${this.title.scrollHeight + this.content.scrollHeight}px`;
}
close() {
this.active = false;
this.el.classList.remove(this.className);
this.style.maxHeight = `${this.title.scrollHeight}px`;
}
toggle() {
this.active ? this.close() : this.open();
}
}
AccordionItem 은 조금 많이 수정이 되었는데,
우선 생성될 때 Accordion에서 받아오는 데이터들을 각각
this.container, this.className에 추가해주었다.
음.. 그리고 기존에 init()에 들어있던 대부분의 문들을 constructor 쪽으로 옮겨주었다.
init에 넣은 경우는 나중에 초기화 하는 부분을 다른곳에서 사용 할 수 있게 할려고 했는데..
딱히 지금은 필요 없을것 같아서 다시 옮겼다.
대신 init 전달받은 className이 해당 dom의 class에 있다면 open을 실행시켜주었다.
이걸로, 초기 html에서 내가 사용하고자하는 클래스 혹은 'active'를 추가해두면
원하는 아코디언 아이템 하나만 펼쳐둘 수 가 있다.
this.accOpen 에 new CustomEvent('accOpen') 으로 이벤트를 하나 생성해준다.
그외에는 딱히 변한 부분은 없고,
open() 매서드 내부에서 dispatchEvent로 생성한 this.accOpen을 호출해준다.
또 open, close 둘다 this.className으로 전달받은 className을 각각 open과 close 시
추가, 삭제해준다.
끝!