Закрыть открытую вкладку по щелчку с помощью ванильного javascript

#javascript #tabs #toggle

#javascript #вкладки #переключить

Вопрос:

Я пытался создать систему вкладок, в которой вкладки закрываются по щелчку. В тот момент, когда я пытаюсь закрыть открытую вкладку, она просто остается открытой.

В основном, когда я нажимаю на вкладку, вкладка открывается, и когда я нажимаю на ту же самую открытую вкладку, вкладка должна закрыться. Это то, чего я пытался достичь.

Пробовал использовать метод toggle() для включения и выключения class .active на целевой вкладке следующим образом:

 this.classList.toggle("active");
 

Однако, похоже, это ничего не дает, поскольку выбранная вкладка всегда остается открытой.

Я считаю, что это очень просто сделать, но я просто не могу в этом разобраться.

Я буду признателен за помощь. Приветствия!

 const tabs = document.querySelectorAll(".tab");
const tabContents = document.querySelectorAll(".tab-content");

for (let i = 0; i < tabs.length; i  ) {
    const tab = tabs[i];
    tab.addEventListener("click", switchClass);
}

function switchClass() {
    for (let i = 0; i < tabs.length; i  ) {
        const tab = tabs[i];
        tab.classList.remove("active");
    }

    for (let i = 0; i < tabContents.length; i  ) {
        const tabContent = tabContents[i];
        tabContent.classList.remove("show-content");
    }

    this.classList.toggle("active");

    const tabDataAttribute = this.getAttribute("data-content");
    document
        .querySelector(`.tab-content[data-content="${tabDataAttribute}"]`)
        .classList.add("show-content");
} 
 ul {
    margin: 0;
    padding: 0;
}

.tab {
    display: inline-block;
    border: 1px solid lightgrey;
    padding: 10px;
    cursor: pointer;
}

.active {
    background: lightgrey;
}

.tab-content {
    display: none;
    padding: 10px;
}

.show-content {
    display: block;
    background: lightgray;
} 
 <ul>
    <li class="tab" data-content="tab1">Tab 1</li>
    <li class="tab" data-content="tab2">Tab 2</li>
    <li class="tab" data-content="tab3">Tab 3</li>
</ul>

<div class="tab-content" data-content="tab1">1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="tab-content" data-content="tab2">2. Vivamus iaculis est in sapien congue, ac condimentum.</div>
<div class="tab-content" data-content="tab3">3. Phasellus aliquam orci neque, non varius quam gravida vel.</div> 

Комментарии:

1. Кажется, здесь все работает просто отлично.

2. Когда я нажимаю на открытую вкладку, она не закрывается.

3. Вы пробовали это прямо здесь, в Stack Overflow? Он работает просто отлично.

4. Например, нажмите на вкладку 1. Он станет активным, верно? Теперь нажмите на ту же вкладку, чтобы закрыть ее. Он останется открытым. В этом проблема. Я хочу иметь возможность щелкнуть по открытой вкладке и закрыть ее.

5. Я вижу. Проверьте мой ответ на решение.

Ответ №1:

Вы не можете использовать .toggle() , потому что первое, что вы делаете при обратном вызове, это удаляете active класс из всех элементов (что правильно), поэтому переключение просто снова включит его (как в текущем случае).

Вместо этого вы должны отслеживать, совпадает ли текущая выбранная вкладка с последней выбранной вкладкой, и действовать соответствующим образом.

В приведенном ниже коде я также объединил циклы и использую синтаксис .forEach() цикла вместо цикла подсчета, что .forEach() проще.

И, если у вас не было какой-либо другой необходимости в этом, вам больше не нужен data-content атрибут.

 const tabs = Array.from(document.querySelectorAll(".tab"));
const tabContents = document.querySelectorAll(".tab-content");

// Use the Array.forEach() syntax for looping as it eliminates
// the need for setting up and managing indexes.
tabs.forEach(function(tab){
  tab.addEventListener("click", switchClass);
});

let priorActive = null;  // Will keep track of last tab made active

function switchClass() {
  // Loop over the tabs
  tabs.forEach(function(tab, index){
    tab.classList.remove("active");             // Remove active
    tabContents[index].classList.add("hidden"); // Hide content with corresponding index
  });

  // Can't use toggle because prior loop just removed the classes, so toggle
  // will always add them back. Instead, you must explicitly turn on or off
  // based on current situation.
  if(priorActive === this){
    this.classList.remove("active");  
    tabContents[tabs.indexOf(this)].classList.add("hidden");
    priorActive = null;
  } else {
    this.classList.add("active");  
    tabContents[tabs.indexOf(this)].classList.remove("hidden");  
    priorActive = this;
  }
} 
 ul {
    margin: 0;
    padding: 0;
}

.tab {
    display: inline-block;
    border: 1px solid lightgrey;
    padding: 10px;
    cursor: pointer;
}

.active {
    background: lightgrey;
}

.tab-content {
    background: lightgray;
    padding: 10px;
}

/* Tab content will have this by default  */
.hidden {
  display:none;
} 
 <ul>
    <li class="tab">Tab 1</li>
    <li class="tab">Tab 2</li>
    <li class="tab">Tab 3</li>
</ul>

<div class="tab-content hidden">1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="tab-content hidden">2. Vivamus iaculis est in sapien congue, ac condimentum.</div>
<div class="tab-content hidden">3. Phasellus aliquam orci neque, non varius quam gravida vel.</div> 

Ответ №2:

сокращенный способ :

вы можете писать действия только внутри container

затем разделите номер вашего элемента (со loop счетчиком) по цели события ( this.target ) каждого клика..

наконец, setAttribute к кнопке вкладки и их содержимому…

я надеюсь, что это помогло…

 let container = document.getElementById("tab-container"); // take container for scoping actions

container.addEventListener("mousedown", (e) => {
    this.tab = document.getElementsByClassName("tab"); // current tab button , clicked..!
    this.content = document.getElementsByClassName("tab-content"); // content of current tab clicked..
    for (let w = 0; w < this.tab.length; w  ) {
        // e.button == 0 is equal to left click by client mouse...
        // e.target take the target and return true
        e.button == 0 ? this.target = this.tab[w].contains(e.target) : false 
        if(this.target){
        this.tab[w].setAttribute("data-tab",true); //set Attr..
        this.content[w].setAttribute("data-content",true); //set Attr..
        }else{
        this.tab[w].removeAttribute("data-tab"); //remove Attr..
        this.content[w].removeAttribute("data-content"); //remove Attr..
        }
    }
}) 
 ul#tab-container{
    margin: 0;
    max-width: 330px;
    background-color: #f3f3f3;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    padding: 0;
}
.tab{
    display: inline-block;
    cursor: pointer;
    padding: 1rem;
    text-align: center;
}
.tab[data-tab="true"]{
    background-color: #fff;
    text-decoration: underline;
    text-underline-offset: 1rem;
}
.tab-content{
    display:none;
    padding: 2rem;
}
.tab-content[data-content="true"]{
    display:inline-block;
} 
 <ul id="tab-container">
    <li class="tab" data-tab="true">Tab 1</li>
    <li class="tab">Tab 2</li>
    <li class="tab">Tab 3</li>
</ul>

<div class="tab-content" data-content="true">1. Lorem ipsum dolor...</div>
<div class="tab-content">2. Vivamus iaculis est...</div>
<div class="tab-content">3. Phasellus aliquam orci...</div>