单击香草 javascript 关闭打开的选项卡

Close open tab on click with vanilla 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>

你不能使用 .toggle() 因为你在回调中做的第一件事是从所有元素中删除 active class (这是正确的做法),所以切换只会把它重新打开(就像当前的情况一样)。

相反,您必须跟踪当前单击的选项卡是否与上次单击的选项卡相同并采取相应措施。

在下面的代码中,我还组合了循环并使用 .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>

shorthand 方式:

你只能在里面写动作 container

然后,根据每次点击的事件目标 (this.target) 将您的元素编号(使用 loop 计数器)分开..

最后,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>