将多个 Vanilla JavaScript 标签添加到同一页面

Adding Multiple Vanilla JavaScript Tabs to the Same Page

使用以下代码的变体,我能够成功添加一组 Vanilla JavaScript 选项卡。

然而如何做 我在 HTML 中使用相同的 类 将多组 JavaScript 选项卡添加到一个页面。

我很难使用 JavaScript 为选项卡选择器和选项卡内容区域创建唯一的动态 ID。如您在 https://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-1/tabs.html 中所见,可访问标签需要这些唯一 ID。

var accessibleTabsContainers = document.querySelectorAll('.accessible-tabs-container');
var tabSelector = document.querySelectorAll('.tab-selectors > li');
var tabContent = document.querySelectorAll('.tab-contents > div');
var largeRandNumber = Math.floor((Math.random() * 1000) + 1000);

accessibleTabsContainers.forEach(function(elem, indexAccessibleTabContainer) {
  elem.setAttribute('data-id', indexAccessibleTabContainer);
  
  tabSelector.forEach(function(singleTabSelector, i) {
   
    var ariaControlTabContent = 'tab-content-' + largeRandNumber + '-' + i + '_' + indexAccessibleTabContainer;
    var tabSelectorId = 'tab-selector-' + largeRandNumber + '-' + i + '_' + indexAccessibleTabContainer;

    singleTabSelector.setAttribute('data-id', i);
    singleTabSelector.setAttribute('id', tabSelectorId);
    singleTabSelector.setAttribute('aria-controls', ariaControlTabContent);

    tabContent[i].setAttribute('data-id', i);
    tabContent[i].setAttribute('tabindex', 0);
    tabContent[i].setAttribute('role', 'tabpanel');
    tabContent[i].setAttribute('id', ariaControlTabContent);
    tabContent[i].setAttribute('aria-labeledby', tabSelectorId);

    if(i === 0) {
      tabSelector[i].setAttribute('aria-pressed', 'true');
    } else {
      tabSelector[i].setAttribute('aria-pressed', 'false');
      tabSelector[i].setAttribute('tabindex', -1);
    }
  });
});  


function onTabSelectorClick(e) {
  
  accessibleTabsContainers.forEach(function(accessibleTabsContainer, indexAccessibleTabContainer) {   
    var tabSelectorSelected = e.target;
    var accessibleTabsContainerSelected = tabSelectorSelected.parentElement.parentElement;
  
    if(!tabSelectorSelected.classList.contains('active-tab-selector')) {
      
     var tabSelectorSelectedFromContainer = accessibleTabsContainerSelected.querySelectorAll('.tab-contents > div');
      console.log(tabSelectorSelectedFromContainer);

     tabSelector.forEach(function(singleTabSelected, i) {
        if(tabSelectorSelected.getAttribute('data-id') === tabContent[i].getAttribute('data-id')) {        
           tabContent[i].classList.add('tab-content-active');
        } else {
           tabSelector[i].classList.remove('active-tab-selector');
           tabSelector[i].setAttribute('aria-pressed', 'false');
           tabSelector[i].setAttribute('aria-selected', 'false');
           tabSelector[i].setAttribute('tabindex', -1);
           tabContent[i].classList.remove('tab-content-active');
        }      
      });

      tabSelectorSelected.classList.add('active-tab-selector');
      tabSelectorSelected.setAttribute('aria-pressed', 'true');        
      tabSelectorSelected.setAttribute('aria-selected', 'true');
      tabSelectorSelected.removeAttribute('tabindex'); 
    }

  });
}

tabSelector.forEach(function(tabSelector) {
  tabSelector.addEventListener('click', onTabSelectorClick);
});
.wrapper {
  max-width: 960px;
  margin: 0 auto;
}

.tab-selectors {
  display: inline-block;
}

.tab-selectors > li {
  padding: 10px;
}

.tab-selectors > .active-tab-selector {
  border: 1px solid #f00; 
}

.tab-content {
  display: inline-block;
}

.tab-contents > div {
  padding: 10px;
  border: 2px solid #000;
  height: 150px;
  width: 150px;
  display: none;
}

.tab-contents > .tab-content-active {
  display: block;
}
<div class="wrapper">
  <h1>Accessible Tabs using Vanilla JavaScript</h1>
  
<div class="accessible-tabs-container">  
  
 <ul role="tablist" aria-lable="Tabs Example" class="tab-selectors">
    <li class="active-tab-selector">Tab Selector 1</li>
    <li>Tab Selector 2</li>
    <li>Tab Selector 3</li>
  </ul>  

  <div class="tab-contents">
    <div class="tab-content-active">
      Tab Content 1
    </div>  
    <div>
      Tab Content 2
    </div>  
    <div>
      Tab Content 3
    </div>
  </div> 
  
  </div>
 
  
<div class="accessible-tabs-container">  
  
 <ul role="tablist" aria-lable="Tabs Example" class="tab-selectors">
    <li class="active-tab-selector">Tab Selector 1</li>
    <li>Tab Selector 2</li>
    <li>Tab Selector 3</li>
  </ul>  

  <div class="tab-contents">
    <div class="tab-content-active">
      Tab Content 1
    </div>  
    <div>
      Tab Content 2
    </div>  
    <div>
      Tab Content 3
    </div>
  </div> 

 </div>  
  
</div>  

我试图在 Vanilla JavaScript (accessibleTabsContainers.forEach) 的第 6 行中生成这些唯一 ID,但它不起作用。

如有任何帮助,我们将不胜感激。

我解决了我自己的问题。在 onTabSelectorClick 函数内部迭代的 forEach 循环中,我重构了代码以添加以下行:

var tabSelectorSelected = e.target;
var accessibleTabsContainerSelected = tabSelectorSelected.closest('.accessible-tabs-container'); 
var tabSelectorsSelectedFromTabs = accessibleTabsContainerSelected.querySelectorAll('ul > li');

然后在 forEach 循环中而不是遍历 tabSelector(引用 var tabSelector = document.querySelectorAll('.tab-selectors > li');)并循环遍历所有选项卡 li 标签,而不仅仅是引用的标签单击元素,我使用 tabSelectorsSelectedFromTabs,它引用其父 div 标记 (var accessibleTabsContainerSelected = tabSelectorSelected.closest('.accessible-tabs-container');) 中的选项卡元素,从选项卡元素 (li 标记) 单击 (var tabSelectorSelected = e.target;).

参见 https://codepen.io/hollyw00d/pen/JjYJWjG。另外,我在此答案中添加了正确的代码。下面是一个比较有用的代码前后说明:

在单击事件处理程序中传递的 onTabSelectorClick 函数中的 forEach 循环片段不正确

var tabSelector = document.querySelectorAll('.tab-selectors > li');

function onTabSelectorClick(e) {
   tabSelector.forEach(function() {
     // Code here
   });
}

更正 forEach 在点击事件处理程序中传递的 onTabSelectorClick 函数中的循环代码段

var tabSelectorSelected = e.target;
var accessibleTabsContainerSelected = tabSelectorSelected.closest('.accessible-tabs-container'); 
var tabSelectorsSelectedFromTabs = accessibleTabsContainerSelected.querySelectorAll('ul > li');

function onTabSelectorClick(e) {
   tabSelectorsSelectedFromTabs.forEach(function() {
     // Code here
   });
}

var accessibleTabsContainers = document.querySelectorAll('.accessible-tabs-container');
var tabSelector = document.querySelectorAll('.tab-selectors > li');
var tabContent = document.querySelectorAll('.tab-contents > div');
var largeRandNumber = Math.floor((Math.random() * 1000) + 1000);

accessibleTabsContainers.forEach(function(elem, indexAccessibleTabContainer) {
  elem.setAttribute('data-id', indexAccessibleTabContainer);
  
  tabSelector.forEach(function(singleTabSelector, i) {
   
    var tabSelectorId = 'tab-selector-' + largeRandNumber + '_' + i + '_' + indexAccessibleTabContainer;
    var ariaControlTabContent = 'tab-content-' + largeRandNumber + '_' + i + '_' + indexAccessibleTabContainer;

    singleTabSelector.setAttribute('data-id', i);
    singleTabSelector.setAttribute('id', tabSelectorId);
    singleTabSelector.setAttribute('aria-controls', ariaControlTabContent);

    tabContent[i].setAttribute('data-id', i);
    tabContent[i].setAttribute('tabindex', 0);
    tabContent[i].setAttribute('role', 'tabpanel');
    tabContent[i].setAttribute('id', ariaControlTabContent);
    tabContent[i].setAttribute('aria-labeledby', tabSelectorId);

    if(i === 0) {
      singleTabSelector.setAttribute('aria-pressed', 'true');
    } else {
      singleTabSelector.setAttribute('aria-pressed', 'false');
      singleTabSelector.setAttribute('tabindex', -1);
    }
  });
});  


function onTabSelectorClick(e) {

    var tabSelectorSelected = e.target;
    var accessibleTabsContainerSelected = tabSelectorSelected.closest('.accessible-tabs-container'); 
    var tabSelectorsSelectedFromTabs = accessibleTabsContainerSelected.querySelectorAll('ul > li');
    var tabContentsSelectedFromContainer = accessibleTabsContainerSelected.querySelectorAll('.tab-contents > div');
  
    if(!tabSelectorSelected.classList.contains('active-tab-selector')) {
      tabSelectorsSelectedFromTabs.forEach(function(singleTabSelected, i) {
        if(tabSelectorSelected.getAttribute('data-id') === tabContentsSelectedFromContainer[i].getAttribute('data-id')) {
          singleTabSelected.classList.add('active-tab-selector');
          singleTabSelected.setAttribute('tabindex', 0);
          singleTabSelected.setAttribute('aria-pressed', 'true');
          tabContentsSelectedFromContainer[i].classList.add('tab-content-active');
        } else {
          singleTabSelected.classList.remove('active-tab-selector');
          singleTabSelected.setAttribute('tabindex', -1);
          singleTabSelected.setAttribute('aria-pressed', 'false');
          tabContentsSelectedFromContainer[i].classList.remove('tab-content-active');
        }

      });
    }
 
}

tabSelector.forEach(function(tabSelector) {
  tabSelector.addEventListener('click', onTabSelectorClick);
});
.wrapper {
  max-width: 960px;
  margin: 0 auto;
}

.tab-selectors {
  display: inline-block;
}

.tab-selectors > li {
  padding: 10px;
}

.tab-selectors > .active-tab-selector {
  border: 1px solid #f00; 
}

.tab-content {
  display: inline-block;
}

.tab-contents > div {
  padding: 10px;
  border: 2px solid #000;
  height: 150px;
  width: 150px;
  display: none;
}

.tab-contents > .tab-content-active {
  display: block;
}
<div class="wrapper">
  <h1>Accessible Tabs using Vanilla JavaScript</h1>
 
<div class="accessible-tabs-container">  
  
  
 <ul role="tablist" aria-lable="Tabs Example" class="tab-selectors">
    <li class="active-tab-selector">Tab Selector 1</li>
    <li>Tab Selector 2</li>
    <li>Tab Selector 3</li>
  </ul>  
  

  <div class="tab-contents">
    <div class="tab-content-active">
      Tab Content 1
    </div>  
    <div>
      Tab Content 2
    </div>  
    <div>
      Tab Content 3
    </div>
  </div> 

  </div>
  
<div class="accessible-tabs-container">  
  
  
 <ul role="tablist" aria-lable="Tabs Example" class="tab-selectors">
    <li class="active-tab-selector">Tab Selector 1</li>
    <li>Tab Selector 2</li>
    <li>Tab Selector 3</li>
  </ul>  
  

  <div class="tab-contents">
    <div class="tab-content-active">
      Tab Content 1
    </div>  
    <div>
      Tab Content 2
    </div>  
    <div>
      Tab Content 3
    </div>
  </div> 

  </div>  
  
</div>