用于切换ARIA和数据属性,并在HTML下拉列表中管理CSS类的实用函数



我有一个下拉实用程序功能,主要是工作。问题在于,当单击非目标按钮或完全在目标元素之外时,如何正确处理按钮的data-textaria属性的切换。

我已经包含了我的window.addEventListener代码,但是已经注释掉了,因为它影响了ul子菜单元素的显示。

我正在零零碎碎地学习香草JavaScript,所以请为新手JS开发人员提供简单的提示和解决方案。谢谢。

const navUtility = (() => {
const buttons = document.querySelectorAll("[data-nav-toggle]");
const containers = document.querySelectorAll("[data-nav-container]");
if (!buttons) {
return;
}
function dropdownToggleHandler() {
buttons.forEach((button) => {
button.addEventListener("click", toggleContainer);
});
}
function toggleContainer(e) {
toggleButtonClass(e.target);
toggleButtonAria(e.target);
toggleButtonDataText(e.target);
toggleContainers(e.target);
}
function toggleButtonClass(button) {
if (button.classList.contains("is-active")) {
button.classList.remove("is-active");
} else {
button.classList.add("is-active");
}
}
function toggleButtonAria(button) {
const expandedValue = button.getAttribute("aria-expanded");
const setValue = expandedValue === "true" ? "false" : "true";
button.setAttribute("aria-expanded", setValue);
}
function toggleButtonDataText(button) {
const originalValue = button.getAttribute("data-text-original");
const swapValue = button.getAttribute("data-text-swap");
if (swapValue === button.textContent) {
button.textContent = button.getAttribute("data-text-original");
} else {
button.setAttribute("data-text-original", button.textContent);
button.textContent = button.getAttribute("data-text-swap");
}
}
function toggleContainers(button) {
const parent = button.closest("[data-nav-container]");
parent.classList.toggle("is-expanded");
document.querySelectorAll(".is-expanded").forEach(function(parentExpanded) {
if (parentExpanded !== parent) {
parentExpanded.classList.remove("is-expanded");
}
});
}
dropdownToggleHandler();
/* window.addEventListener('click', function(e) {
containers.forEach((container) => {
if (e.target !== container) {
container.classList.remove("is-expanded");
}
});
}); */
})();
nav {
position: relative;
}
nav>ul {
width: 21rem;
max-height: 0;
position: absolute;
right: auto;
left: 0;
z-index: 5;
visibility: hidden;
background-color: grey;
transition: max-height 200ms ease-out;
}
nav.is-expanded>ul {
max-height: 4000px;
visibility: visible;
}
<nav class="" data-nav-container="want-to-navigation" aria-label="Site tools navigation">
<button aria-expanded="false" class="" data-nav-toggle="want-to-navigation" data-text-swap="Close" data-text-original="I Want To...">Close</button>
<ul id="want-to-navigation" class="menu">
<li>
<a>Apply For</a>
<ul class="sub-menu">
<li>
<a href="#">Development Permits</a>
</li>
<li>
<a href="#">Dust Suppressant</a>
</li>
<li>
<a href="#">Fire Permit</a>
</li>
<li>
<a href="#">Employment</a>
</li>
<li>
<a href="#">Subdivision</a>
</li>
</ul>
</li>
</ul>
</nav>
<nav class="" data-nav-container="quick-links-navigation" aria-label="Site quick links navigation">
<button aria-expanded="false" class="" data-nav-toggle="quick-links-navigation" data-text-swap="Close" data-text-original="Quicklinks">Close</button>
<ul id="quick-links-navigation">
<li>
<a href="#">Community Guide</a>
</li>
<li>
<a href="#">Notice of Development</a>
</li>
<li>
<a href="#">Workshops &amp; Courses</a>
</li>
<li>
<a href="#">Council Business</a>
</li>
</ul>
</nav>

您在窗口事件侦听器中添加的条件没有帮助您。而不是比较container与事件目标元素,您必须检查container是否包含事件目标元素。如果事件在nav内,则忽略,否则将container类列表切换为.is-expanded

替换

if (e.target !== container) {
container.classList.remove("is-expanded");
}

if (!container.contains(e.target)) {
container.classList.remove("is-expanded");
}

可以解决你的问题。


与快速修复

window.addEventListener('DOMContentLoaded', function(){
const navUtility = (() => {
const buttons = document.querySelectorAll("[data-nav-toggle]");
const containers = document.querySelectorAll("[data-nav-container]");

if (!buttons) {
return;
}

function dropdownToggleHandler() {
buttons.forEach((button) => {
button.addEventListener("click", toggleContainer);
});
}

function toggleContainer(e) {
toggleButtonClass(e.target);
toggleButtonAria(e.target);
toggleButtonDataText(e.target);


toggleContainers(e.target);
}

function toggleButtonClass(button) {
if (button.classList.contains("is-active")) {
button.classList.remove("is-active");
} else {
button.classList.add("is-active");
}
}

function toggleButtonAria(button) {
const expandedValue = button.getAttribute("aria-expanded");
const setValue = expandedValue === "true" ? "false" : "true";
button.setAttribute("aria-expanded", setValue);
}

function toggleButtonDataText(button) {
const originalValue = button.getAttribute("data-text-original");
const swapValue = button.getAttribute("data-text-swap");
if (swapValue === button.textContent) {
button.textContent = button.getAttribute("data-text-original");
} else {
button.setAttribute("data-text-original", button.textContent);
button.textContent = button.getAttribute("data-text-swap");
}
}

function toggleContainers(button) {
const parent = button.closest("[data-nav-container]");
parent.classList.toggle("is-expanded");
document.querySelectorAll(".is-expanded").forEach(function(parentExpanded) {
if (parentExpanded !== parent) {
parentExpanded.classList.remove("is-expanded");
}
});
}

dropdownToggleHandler();

window.addEventListener('click', function(e) {
containers.forEach((container) => {
if (!container.contains(e.target)) {
container.classList.remove("is-expanded");
}
});
});
})();
})
nav {
position: relative;
}
nav>ul {
width: 21rem;
max-height: 0;
position: absolute;
right: auto;
left: 0;
z-index: 99;
visibility: hidden;
background-color: grey;
transition: max-height 200ms ease-out;
}
nav.is-expanded>ul {
max-height: 4000px;
visibility: visible;
}
<nav tabindex="-1"  class="" data-nav-container="want-to-navigation" aria-label="Site tools navigation">
<button aria-expanded="false" class="" data-nav-toggle="want-to-navigation" data-text-swap="Close" data-text-original="I Want To...">Close</button>
<ul id="want-to-navigation" class="menu">
<li>
<a>Apply For</a>
<ul class="sub-menu">
<li>
<a href="#">Development Permits</a>
</li>
<li>
<a href="#">Dust Suppressant</a>
</li>
<li>
<a href="#">Fire Permit</a>
</li>
<li>
<a href="#">Employment</a>
</li>
<li>
<a href="#">Subdivision</a>
</li>
</ul>
</li>
</ul>
</nav>
<nav tabindex="-1" class="" data-nav-container="quick-links-navigation" aria-label="Site quick links navigation">
<button aria-expanded="false" class="" data-nav-toggle="quick-links-navigation" data-text-swap="Close" data-text-original="Quicklinks">Close</button>
<ul id="quick-links-navigation">
<li>
<a href="#">Community Guide</a>
</li>
<li>
<a href="#">Notice of Development</a>
</li>
<li>
<a href="#">Workshops &amp; Courses</a>
</li>
<li>
<a href="#">Council Business</a>
</li>
</ul>
</nav>

这将解决隐藏问题,你需要改变相应的按钮标题。

(更新)

最小化
代码以避免冗长的post

虽然这工作得很好,你必须尝试onBlur事件来处理这样的活动,而不是检查点击整个文档的目标元素

你可以用标签代替按钮,因为标签允许你用for属性与其他元素关联。

window.addEventListener("DOMContentLoaded",handleDomOnLoad);function handleDomOnLoad(a){(()=>{let a=document.querySelectorAll("[data-nav-toggle]"),b=document.querySelectorAll("[data-nav-container]");function c(a){d(a.target),e(a.target),f(a.target),g(a.target)}function d(a){a.classList.contains("is-active")?a.classList.remove("is-active"):a.classList.add("is-active")}function e(a){let b=a.getAttribute("aria-expanded");a.setAttribute("aria-expanded","true"===b?"false":"true")}function f(a){a.getAttribute("data-text-original");let b=a.getAttribute("data-text-swap");b===a.textContent?a.textContent=a.getAttribute("data-text-original"):(a.setAttribute("data-text-original",a.textContent),a.textContent=a.getAttribute("data-text-swap"))}function g(a){let b=a.closest("[data-nav-container]");b.classList.toggle("is-expanded"),document.querySelectorAll(".is-expanded").forEach(function(a){a!==b&&a.classList.remove("is-expanded")})}
function handleOnBlur(e) {
if (!e.currentTarget.contains(e.relatedTarget))
e.target.classList.remove("is-expanded");
};
document.querySelectorAll('li a[href]').forEach(element => element.addEventListener('click', function(e){
console.log(e.target.textContent);
document.querySelectorAll('nav').forEach(n=>n.classList.remove("is-expanded")); //can fetch specific parent by traversing
}))
,a&&(a.forEach(a=>{a.addEventListener("click",c)}),
document.querySelectorAll("[data-nav-container]").forEach(
a=>{
a.addEventListener("blur",handleOnBlur)
}
)
)})()}
*{ font-family: sans-serif; }
nav { position: relative; background-color: #cfcfcf; margin: 5px; padding: 8px 16px; border-radius: 5px; display: inline-block; }
nav>ul { padding: 8px 16px; width: 21rem; position: absolute; right: auto; left: 0; z-index: 5; visibility: hidden; background-color: #cfcfcf78; transition: max-height 200ms ease-out; border-radius: 5px; }
nav.is-expanded>ul { height: auto; visibility: visible; }
nav ul li { margin: 0px; list-style-type: none; }
nav li ul li { padding:10px; }
<nav tabindex="-1" id="nav1" data-nav-container="want-to-navigation" aria-label="Site tools navigation">
<label aria-expanded="false" for='nav1' class="" data-nav-toggle="want-to-navigation" data-text-swap="Close" data-text-original="I Want To...">Close</label>
<ul id="want-to-navigation" class="menu">
<li>
<a>Apply For</a>
<ul class="sub-menu">
<li><a href="#">Development Permits</a></li>
<li><a href="#">Dust Suppressant</a></li>
<li><a href="#">Fire Permit</a></li>
<li><a href="#">Employment</a></li>
<li><a href="#">Subdivision</a></li>
</ul>
</li>
</ul>
</nav>

最新更新