사이드 탭을 여는 경우 다른 탭이 열릴 때 완전히 닫히기 - java script
조회수 796회
사이드 탭을 만드는 중인데요. 기본적인 화면에는 얇고 긴 사각형 안에 아이콘만 들어있고, 해당하는 아이콘을 누르는 경우 그 탭이 확장되어 열리는 방식입니다. 각각의 탭을 누르고 닫는 것에는 성공했지만, 여러 탭을 동시에 누르는 경우, 예를 들어 가->나->다 의 순서로 열었다면 역순인 다->나->가 로 닫았을 때 문제는 없지만, '나'를 먼저 닫거나 '가'를 닫게 되면 오류가 발생해 탭이 열리지 않습니다. 제 생각에는 다른 탭을 눌렀을 때 기존의 탭이 완전히 닫히지 않아 발생하는 문제인 것 같지만 해결할 방도를 찾지 못하고 이렇게 질문합니다. 어떻게 if 문, 혹은 다른 함수를 구성해야 원하는 방법대로 가능할까요 ? 아래에는 js 코드 입니다. 수정) html 과 css 코드도 첨부합니다 !! 감사합니다 !
let sidebar = document.querySelector(".sidebar");
let project = document.querySelector(".project");
let friends = document.querySelector(".friends");
let todo = document.querySelector(".todo");
let calendar = document.querySelector(".calendar");
let closeBtn = document.querySelector("#btn");
let projectBtn = document.querySelector(".bx-grid-alt");
let friendsBtn = document.querySelector(".bx-user");
let todoBtn = document.querySelector(".bx-chat");
let calendarBtn = document.querySelector(".bx-folder");
closeBtn.addEventListener("click", ()=>{
sidebar.classList.toggle("open");
menuBtnChange();//calling the function(optional)
});
projectBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
project.classList.toggle("open");
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
friendsBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
friends.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
todoBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
todo.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
calendarBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
calendar.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
// following are the code to change sidebar button(optional)
function menuBtnChange() {
if(sidebar.classList.contains("open")){
closeBtn.classList.replace("bx-menu", "bx-menu-alt-right");//replacing the iocns class
}else {
closeBtn.classList.replace("bx-menu-alt-right","bx-menu");//replacing the iocns class
}
}
<!DOCTYPE html>
<!-- Created by CodingLab |www.youtube.com/CodingLabYT-->
<html lang="ko" dir="ltr">
<head>
<meta charset="UTF-8">
<!--<title> Responsive Sidebar Menu | CodingLab </title>-->
<link rel="stylesheet" href="stylesss.css">
<!-- Boxicons CDN Link -->
<script src="https://kit.fontawesome.com/29ee0bc57e.js" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToasTooL</title>
</head>
<body>
<div class="sidebar">
<div class="logo-details">
<i class='bx bx-menu' id="btn"></i>
</div>
<ul class="nav-list">
<li>
<nav class="project"></nav>
<a href="#">
<i class='bx bx-grid-alt'></i>
</a>
<span class="tooltip">Project</span>
</li>
<li>
<nav class="friends"></nav>
<a href="#">
<i class='bx bx-user'></i>
</a>
<span class="tooltip">Friends</span>
</li>
<li>
<nav class="todo">
<div id="tabwrap">
<button class="menu1 on">Project</button>
<button class="menu2">Personal</button>
<div class="board1" -ms-overflow-style: none;>
<header>
<input type="text" id="myInput1" placeholder="Tings to be done in the project..." autocomplete="off" />
<span class="addBtn1" id="add_button1">+</span>
</header>
<ul class="ful" id="myUL1"></ul>
<script script src="script.js"></script>
</div>
<div class="board2">
<header>
<input type="text" id="myInput2" placeholder="Tings to be done in personal..." autocomplete="off" />
<span class="addBtn2" id="add_button2">+</span>
</header>
<ul id="myUL2"></ul>
<script script src="scriptt.js"></script>
</div>
</div>
</nav>
<a href="#">
<i class='bx bx-chat'></i>
</a>
<span class="tooltip">Todo</span>
</li>
<li>
<nav class="calendar"></nav>
<a href="#">
<i class='bx bx-folder'></i>
</a>
<span class="tooltip">Calendar</span>
</li>
<li class="profile">
<div class="profile-details">
<img src="profile.jpg" alt="profileImg">
<div class="name_job">
<div class="name">Prem Shahi</div>
<div class="job">Web designer</div>
</div>
</div>
<i class='bx bx-log-out' id="log_out"></i>
</li>
</ul>
</div>
<section class="home-section">
<div class="text">Dashboard</div>
</section>
<iframe src="www.wikipedia.org"></iframe>
<script script src="scripttt.js"></script>
</body>
</html>
let sidebar = document.querySelector(".sidebar");
let project = document.querySelector(".project");
let friends = document.querySelector(".friends");
let todo = document.querySelector(".todo");
let calendar = document.querySelector(".calendar");
let closeBtn = document.querySelector("#btn");
let projectBtn = document.querySelector(".bx-grid-alt");
let friendsBtn = document.querySelector(".bx-user");
let todoBtn = document.querySelector(".bx-chat");
let calendarBtn = document.querySelector(".bx-folder");
closeBtn.addEventListener("click", ()=>{
sidebar.classList.toggle("open");
menuBtnChange();//calling the function(optional)
});
projectBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
project.classList.toggle("open");
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
friendsBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
friends.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
todoBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
todo.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(calendar.classList.contains("open")){
calendar.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
calendarBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn
calendar.classList.toggle("open");
if(project.classList.contains("open")){
project.classList.toggle("close");
}
if(friends.classList.contains("open")){
friends.classList.toggle("close");
}
if(todo.classList.contains("open")){
todo.classList.toggle("close");
}
menuBtnChange(); //calling the function(optional)
});
// following are the code to change sidebar button(optional)
function menuBtnChange() {
if(sidebar.classList.contains("open")){
closeBtn.classList.replace("bx-menu", "bx-menu-alt-right");//replacing the iocns class
}else {
closeBtn.classList.replace("bx-menu-alt-right","bx-menu");//replacing the iocns class
}
}
-
(•́ ✖ •̀)
알 수 없는 사용자
2 답변
-
HTML, CSS 요청드렸는데 늦게 답변드린점 죄송해요 (회사에서 할거없을때 답변다는 편이라... ㅎㅎ;;)
일단 문제 발생원인은 메뉴클릭시 DOM Element 들의 class 변경상태들을 보면 나오는데요 순서대로 클릭하지 않을시에 open close 가 같이 class 에 들어가면서 되는거라서.. 확실히 open / close 하나의 클래스만 들어가게끔 해주시면 되요
projectBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn if(project.classList.contains("close")){ project.classList.toggle('close'); } project.classList.toggle("open"); if(friends.classList.contains("open")){ friends.classList.toggle('open'); friends.classList.toggle("close"); } if(todo.classList.contains("open")){ todo.classList.toggle('open'); todo.classList.toggle("close"); } if(calendar.classList.contains("open")){ calendar.classList.toggle('open'); calendar.classList.toggle("close"); } menuBtnChange(); //calling the function(optional) }); friendsBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn if(friends.classList.contains("close")){ friends.classList.toggle('close'); } friends.classList.toggle("open"); if(project.classList.contains("open")){ project.classList.toggle('open'); project.classList.toggle("close"); } if(todo.classList.contains("open")){ todo.classList.toggle('open'); todo.classList.toggle("close"); } if(calendar.classList.contains("open")){ calendar.classList.toggle('open'); calendar.classList.toggle("close"); } menuBtnChange(); //calling the function(optional) }); todoBtn.addEventListener("click", ()=>{ // Sidebar open when you click on the search iocn if(todo.classList.contains("close")){ todo.classList.toggle('close'); } todo.classList.toggle("open"); if(project.classList.contains("open")){ project.classList.toggle('open'); project.classList.toggle("close"); } if(friends.classList.contains("open")){ friends.classList.toggle('open'); friends.classList.toggle("close"); } if(calendar.classList.contains("open")){ calendar.classList.toggle('open'); calendar.classList.toggle("close"); } menuBtnChange(); //calling the function(optional) });
위 코드는 비효율적이고 버그 수정이나 기능 수정시 시간이 오래걸려 실제 적용방식은 아래와 같이 해주시면 될거 같습니다.
/* 상동 */ var q = new Array(project, friends, todo, calendar); var e = new Array(projectBtn, friendsBtn, todoBtn, calendarBtn); for (i in e) { e[i].addEventListener("click", function() { menuBtnChange(this) }); } function menuBtnChange(w) { for(i in e){ if (w === e[i]) { if (q[i].classList.contains('close')) q[i].classList.remove('close'); q[i].classList.add('open'); } else { if (q[i].classList.contains('open')){ q[i].classList.remove('open'); q[i].classList.add('close'); } } } if(sidebar.classList.contains("open")){ closeBtn.classList.replace("bx-menu", "bx-menu-alt-right");//replacing the iocns class }else { closeBtn.classList.replace("bx-menu-alt-right","bx-menu");//replacing the iocns class } }
- 헉 !! 아코디언 형식을 찾아보려니 가로형은 잘 없고, 그마저도 무조건 하나의 섹션은 띄워져 있어야 해서 고전 중이었는데, 덕분에 진행도를 확 높일 수 있을 것 같습니다 !!!! 하단의 코드를 사용하려니 나와 있는 섹션이 다시 들어가질 않아서 제가 그 부분만 수정하면 정말로 제가 생각했던 그대로의 UI가 완성되네요 ! 늦게라도 잊지 않으시고 친절하고 자세한 답변 달아주신 점 정말 감사합니다. 정말 복 받으실 거예요 😊 알 수 없는 사용자 2021.10.21 19:27
- 아뇨. 도움이 되었다니 감사합니다 :D 김호원 2021.10.22 09:32
-
데모를 보니 생각보다 본격적인 작업이어서 제 수준에서는 뭐라고 함부로 말 얹기는 어렵지만... 저는 UI 구현하다가 막히면 부트스트랩 등 각종 프레임워크의 구현체와 jquery 플러그인들을 살펴보는 편인데요, 탭은 보통 다음과 같이 구현들을 하더군요.
.active
클래스가 붙은 것은 표시되고, 안 붙은 것은 안 표시되도록 CSS를 작성합니다.- 언제 무엇이
.active
클래스를 갖는지 통제하는 JS 스크립트를 작성합니다.
그리고 이 통제를 어떻게 작성하느냐에 따라서 그건 탭이 되기도 하고 아코디언이 되기도 하고 천차만별이 되지요. 그리고 제 생각에 질문자님이 구현하려고 하시는 것은 아코디언에 가깝습니다. 펼쳐질 수 있는 것이 최소 0개 최대 1개이기 때문이죠.
부트스트랩의 경우, 제 경험으로 배운 것이 맞다면, 아코디언은 다음과 같이 통제를 합니다.
- 일단은 전부
.active
를 없앤다. - 탭을 하나 클릭했을 때, 그 탭에 딸린 패널("pane"이라는 어려운 영단어로 부름")의
.active
를 토글한다. - 다른 패널은 묻지도 따지지도 않고 무조건
.active
를 없앤다.
확실히, 이렇게 하면, active한 패널은 최대 1개이고, 그 패널의 탭을 다시 누르면 모든 패널이 잘 닫히는 등, 크게 비논리적인 행동 없이 기대한 대로 잘 작동할 것 같은데 어떠신가요?
코드 한 줄 없이 다 말로 때웠습니다만, 여기서부터는 질문자님이 스스로 자기 코드를 돌아보고 어떻게 리팩토링할 것인지를 고민하는 단계에 들어가셔야 합니다. 결국, 질문자님이 정말 원하는 최종 결과가 뭔지는 질문자님이 가장 잘 알고 계십니다. 한번 잘 생각해 보시고 차분히 가 보세요. 도움이 됐기를 바라며 이만 줄이겠습니다.
사족 1. 질문 자체에만 답을 드리자면... 이상 현상이 발생하고 있는 이유는
.open
과.close
가 동시에 사용되고 있기 때문일 것으로 보입니다. 복붙 코드와 CSS의 나열로 인해 우선순위가 꼬여 있고 그 꼬인 우선순위를 추적하기도 매우 어려울 것입니다. CSS는 나중에 나오는 정의가 더 중요하므로,.friend.close
이후에.calendar.open
이 적혀 있는 한, 캘린더의 열림 여부가 친구 목록창의 닫힘 여부보다 더 중요합니다. 아닌가? 아! 헷갈리네요.사족 2. 일상 생활에서는 open의 반대가 close입니다만, 공학의 세계에서 open의 반대는 not open입니다. 왜 그러냐면, open and close라든가 not open and not close라든가 하는 경우가 이론상으로는 가능하기 때문입니다. (지금 메뉴들이 바로 그럴 거에요.) 이 부분 상당히 중요한 개념인 관계로 굳이 아는체를 해 봅니다. 다른 건 몰라도 이건 잊지 말고 이후 유념해 주세요.
- 정말 정성스러운 답변 감사합니다 ! 태그 해주신 사이트를 읽어보니 정말로 탭이 아니라 아코디언에 더 가까울 지도 모르겠네요 !! 일단은 더 공부해보고 active 상태를 만드는 것을 우선으로 수정해 나가보도록 하겠습니다 ! 급한 프로젝트여서 복붙을 많이 했는데 이런 문제가 생길 줄이야 ,,,, 덧붙여 주신 이야기도 꼼꼼히 참고하도록 하겠습니다 . 정말 감사해요 !!! 😄 알 수 없는 사용자 2021.10.18 23:23
댓글 입력