티스토리 뷰
탭 메뉴 구현을 위한 설계도
탭 메뉴를 직접 짤 때 우리는 크게 세 가지 단계를 거칩니다.
- 선택 (Selection): 클릭할 '탭 버튼들'과 보여줄 '컨텐츠들'을 모두 불러옵니다. 🖱️
- 반복 (Loop): 여러 개의 버튼 중 어떤 것이 클릭될지 모르니, 모든 버튼에 "클릭하면 실행해!"라는 이벤트를 미리 걸어둡니다. 🔄
- 제어 (Control): 버튼이 클릭되면 모든 active 클래스를 일단 다 지우고, **방금 클릭한 그 버튼(과 연결된 컨텐츠)**에만 active 클래스를 붙입니다. ✨
첫 번째 단계: 요소 선택하기
퍼블리셔분들은 HTML 구조를 먼저 보시죠? 보통 아래와 같은 구조일 거예요.
<ul class="tab-group">
<li class="tab-btn active">메뉴 1</li>
<li class="tab-btn">메뉴 2</li>
</ul>
<div class="content-group">
<div class="tab-content active">내용 1</div>
<div class="tab-content">내용 2</div>
</div>
자바스크립트에서 tab-btn이라는 클래스를 가진 요소를 모두 가져와서 btns라는 변수에 담으려고 합니다. 이때 querySelector 대신 여러 개를 한꺼번에 가져오는 메서드를 써야 하는데요.
여기서 첫 번째 질문입니다! 여러 개의 요소를 배열 형태(NodeList)로 한 번에 담을 때 사용하는 자바스크립트 명령어가 무엇인지 혹시 알고 계신가요? (힌트: document.querySelector____)
document.querySelector가 하나만 가져온다면, 모두(All) 가져오는 메서드는 이름 뒤에 그 단어가 붙습니다.
바로 document.querySelectorAll('.tab-btn') 입니다. 🔍
이렇게 가져온 결과물은 배열과 비슷한 형태(NodeList)로 담기게 되는데, 퍼블리셔 입장에서 아주 유용한 특징이 있습니다. 바로 forEach라는 반복문을 사용해서 버튼 하나하나에 이벤트를 걸어줄 수 있다는 점이죠.
2단계: 반복문으로 이벤트 걸기 (Loop)
이제 가져온 버튼들(btns)을 하나씩 꺼내서 "클릭" 이벤트를 심어줄 차례입니다.
const btns = document.querySelectorAll('.tab-btn');
btns.forEach((btn, index) => {
btn.addEventListener('click', () => {
// 여기에 클릭했을 때 일어날 일을 적습니다.
console.log(index + "번째 버튼이 클릭됨!");
});
});
여기서 index라는 매개변수가 아주 중요한 역할을 합니다. 0번 버튼을 누르면 0번 컨텐츠를 보여줘야 하니까요.
직접 설계해보기
탭 메뉴의 핵심은 **"나머지는 다 끄고, 내가 누른 것만 켜기"**입니다. 버튼을 클릭했을 때, 가장 먼저 모든 버튼과 컨텐츠에서 active 클래스를 제거하는 과정이 필요한데요.
왜 하나하나 지우지 않고 **"전체를 다 지우는 과정"**을 먼저 거치는 것이 코드를 짤 때 더 유리할까요?
탭이 3개일 때, 5개일 때마다 코드를 일일이 수정하는 것은 비효율적이죠. 그래서 말씀하신 대로 **"일단 모두 지우고(초기화), 선택한 것만 켠다"**는 방식이 가장 깔끔하고 확장성이 좋습니다.
탭 메뉴 완성해보기
이제 우리가 설계한 로직을 코드로 합쳐보겠습니다.
const btns = document.querySelectorAll('.tab-btn');
const contents = document.querySelectorAll('.tab-content');
btns.forEach((btn, index) => {
btn.addEventListener('click', () => {
// 1. 모든 버튼과 컨텐츠에서 'active' 클래스를 제거 (초기화)
btns.forEach(item => item.classList.remove('active'));
contents.forEach(item => item.classList.remove('active'));
// 2. 클릭된 버튼과 그에 맞는 순서(index)의 컨텐츠에만 클래스 추가
btn.classList.add('active');
contents[index].classList.add('active');
});
});
함수로 정의하고 호출하기
/* 탭 메뉴: 모든 클래스 제거 후 나만 추가 */
function handleTab(btns, contents, index) {
btns.forEach(btn => btn.classList.remove('active'));
contents.forEach(con => con.classList.remove('active'));
btns[index].classList.add('active');
contents[index].classList.add('active');
}
탭 메뉴 호출 (인덱스 활용)
탭 메뉴는 "몇 번째 버튼을 눌렀느냐"가 중요합니다. forEach의 index를 함수에 전달하는 것이 핵심이에요.
const tabBtns = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
tabBtns.forEach((btn, index) => {
btn.addEventListener('click', () => {
// 미리 만들어둔 함수를 호출하면서 (버튼묶음, 컨텐츠묶음, 누른순서)를 전달!
handleTab(tabBtns, tabContents, index);
});
});
💡 실무 팁: this를 쓸 때 주의할 점
함수 안에서 this를 쓰고 싶다면, addEventListener의 콜백 함수를 화살표 함수(() => {})가 아닌 **일반 함수(function() {})**로 써야 합니다.
- 화살표 함수: this가 내가 클릭한 버튼이 아닐 수 있음.
- 일반 함수: this가 정확히 클릭된 그 요소를 가리킴.
※ 해당 내용은 Google Gmini3.0과 함께 공부한 내용입니다.
'WEB > JavaScript' 카테고리의 다른 글
| [JavaScript] 탭메뉴, 아코디언, 모달 (0) | 2026.01.03 |
|---|---|
| [JavaScript] 모달 팝업 (0) | 2026.01.03 |
| [JavaScript] 아코디언 코드 (0) | 2026.01.03 |
| [JavaScript] 공지사항 더보기 데이터 가져오기 (0) | 2026.01.03 |
| [JavaScript] 스크롤에 따른 이벤트 (0) | 2026.01.03 |
- Total
- Today
- Yesterday
- 테스크탑무선랜카드 #무선랜카드 #아이피타이무선랜카드 #a3000mini #무선랜카드추천
- 쇼팬하우어 #좋은책
- 파비콘사이즈
- 연명의료결정제도 #사전연명의료의향서 #사전연명의료의향서등록기관 #광주사전연명의료의향서
- echart
- lg그램pro #lg그램 #노트북 #노트북추천 #lg노트북
- 파비콘 #파비콘 사이트에 적용
- 자바스크립트countiue
- 자바스크립트정규표현식
- css미디어쿼리 #미디어쿼리 #mediaquery
- SQL명령어 #SQL
- jdk #jre
- 와이파이증폭기추천 #와이파이설치
- 자바스크립트 #javascript #math
- 탭메뉴자바스크립트
- thymeleaf
- 자바스크립트break
- 바지락칼국수 #월곡동칼국수 #칼국수맛집
- 썬크림 #닥터지썬크림 #내돈내산 #내돈내산썬크림 #썬크림추천 #spf50썬크림 #닥터지메디유브이울트라선
- 증폭기 #아이피타임증폭기
- sw기술자평균임금 #2025년 sw기술자 평균임금
- 무료폰트 #무료웹폰트 #한수원한돋움 #한수원한울림 #한울림체 #한돋움체
- 광주분식 #광주분식맛집 #상추튀김 #상추튀김맛집 #광주상추튀김
- jQuery #jQuery이미지슬라이드 #이미지슬라이드
- 좋은책 #밥프록터 #부의원리
- iptime와이파이증폭기 #와이파이증폭기설치
- 정보처리기사 #정보처리기사요약 #정보처리기사요점정리
- // 사진직: 데이터가 없으면 DEFAULT_IMG 사용 const profileSrc = (d.img && d.img !== "") ? d.img : DEFAULT_IMG;('#user-photo').attr('src'
- ajax
- 좋은책
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
