提问人:Tom 提问时间:11/14/2023 更新时间:11/15/2023 访问量:67
Javascript 函数在前几次迭代中有效,然后失败
Javascript function works for first few iterations then fails
问:
我们使用 JS 来打开和关闭我们网站上的导航面板。每个导航栏选项都是一个 href 链接,用于未启用 JS 的人访问我们的网站。我们正在使用 JS 拦截链接并通过 CSS 更改打开面板。
该函数在调用的前几次运行良好,然后失败并遵循默认链接。在失败之前似乎没有固定的迭代次数,但 nvbtn3 似乎是它失败最多的一个。
不知道如何找到治疗方法。这几乎就像它超载并退出一样。有什么建议吗?
在导航栏上查找点击的事件委派部分
$('mstrwrap').addEventListener('click', function(e) {
// set eventlisteners for all A HREF links
if (e.target.nodeName === 'A') {
e.preventDefault();
// check if is navbar link
if ((e.target.id.includes('nvbtn'))) {
// determine matching nav panel
const nvpnl = e.target.id;
const lk = 'nav' + nvpnl.match(/\d+/g);
// open nav panel
openNav(lk, nvpnl);
}
// end if navbar link
// lots more possible targets
}
}
用于打开导航菜单的JS函数
function openNav(x, y) {
// if already open, close it
if ($(x).style.maxHeight === '100vh') {
// close
$(x).style.maxHeight = '0';
$(x).style.zIndex = '';
$(y).classList.remove('nvopen');
$('nvbar').classList.remove('nvopen2');
}
// close any that are open, then open target
else {
// close all pnl, open specified pnl
const targets = document.querySelectorAll('[id^="nav"]');
for (let i = targets.length; i--;) {
targets[i].style.maxHeight = '0';
targets[i].style.zIndex = '';
}
const nvbtns = document.querySelectorAll('[id^="nvbtn"]');
for (let i = nvbtns.length; i--;) {
nvbtns[i].classList.remove('nvopen');
}
$(x).style.maxHeight = '100vh';
$(x).style.zIndex = '5';
$(y).classList.add('nvopen');
$('nvbar').classList.add('nvopen2');
}
}
我们使用伪jQuery样式变量
var $ = function (selector) {
return document.getElementById(selector);
};
导航栏是简单的 href 链接
<a href="https://example.com/menu1.htm" id="nvbtn1">Menu 1</a>
<a href="https://example.com/menu2.htm" id="nvbtn2">Menu 2</a>
<a href="https://example.com/menu3.htm" id="nvbtn3">Menu 3</a>
答:
Bergi 在评论中是对的,这就是为什么我们要求提供更多可能的细节并要求一个可重复的例子,因为在简化问题的代码时,你摆脱了问题(试图找到导致你的问题的最小例子可以帮助你自己解决它,这是一个很好的思考过程)
您的链接不仅仅是文本,它们包含以下元素:
<a class="xp" href="..." id="nvbtn3">Book <span class="nvt">|</span><span class="nvd">Now ✎</span> Ask Us </a>
因此,当您单击文本之间的小图标时,就会发生错误,因为测试失败if (e.target.nodeName === 'A') { }
编辑(可能更简单):
还有另一种解决方案,在链接内的所有元素上使用 CSS,例如 .然后,该事件不应在跨度上触发,而应在父链路上触发。pointer-events: none;
<span>
源语言:
为了解决这个问题,您可以使用以下测试,但要小心,因为元素结构的更改可能会弄乱它(一个可靠的解决方案是递归测试父元素,直到你发现你是否在链接中):<a>
if (e.target.nodeName === 'A' || (e.target.nodeName === 'SPAN' && e.target.parentNode.nodeName === 'A')) {
//your code
}
您可以添加其他测试,例如 的类(如果它适合您的用例)。<span>
评论
if (e.target.closest('a'))
pointer-events: none;
另一种设计方案:
将 javascript 禁用菜单放在开始和结束标签对中。如果属性仅用于 JS,而不用于样式设置,则可能省略属性。<noscript>...</script>
id
<noscript>
<a href="https://example.com/menu1.htm">Menu 1</a>
<a href="https://example.com/menu2.htm">Menu 2</a>
<a href="https://example.com/menu3.htm">Menu 3</a>
</noscript>
将菜单元素放在样式属性设置为的元素中,并设置用于键导航的选项卡索引。nav
none
<nav style="display: none">
<span class="navbtn" id="nvbtn1" tabindex="0">Menu 1</span>
<span class="navbtn" id="nvbtn2" tabindex="0">Menu 2</span>
<span class="navbtn" id="nvbtn3" tabindex="0">Menu 3</span>
</nav>
在 JS 启动代码中,解析正文后,从元素中删除样式:display:none
nav
document.querySelectAll('nav').forEach(el=>{
el.style.display="revert";
}
这种设计应该适用于客户端在关闭 JS 时遇到麻烦的浏览器。它不适用于不支持 CSS 和元素属性的浏览器。
style
元素的内容不必是链接,上面的示例显示了旨在由 Click 或键盘事件处理程序管理的构成子元素。实际的子元素将取决于应用程序(对于页面内容中的导航,可以是链接)。
nav
nav
主要的好处是不再需要编写或调试“拦截链接”的代码。
下一个:如何在函数中传递克隆的元素?
评论
if (e.target.nodeName === 'A')
for (let i = nvbtns.length; i--;)