提问人:Rocky Barua 提问时间:7/20/2023 更新时间:7/30/2023 访问量:115
子元素的 click 事件被父元素的 event.stopPropagation 阻止
Child element's click event prevented by parent's event.stopPropagation
问:
在我的(实时站点)上,我使用“nice-select”库创建了一个选择元素。此 select 元素嵌套在下拉菜单中,该下拉菜单具有自己的 JavaScript 文件
function singleMenu(targetId, menuId, show = false) {
const targetElement = document.getElementById(targetId);
const menuElement = document.getElementById(menuId);
// Initial state
if (show) {
// show dropdown
menuElement.style.display = "block";
targetElement.classList.add("active");
} else {
// hide dropdown
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
// Toggle menu visibility when target element is clicked
targetElement.addEventListener("click", () => {
show = !show;
if (show) {
// show dropdown
menuElement.style.display = "block";
targetElement.classList.add("active");
} else {
// hide dropdown
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
});
// Close menu if clicked outside of container
document.addEventListener("click", (event) => {
if (!targetElement.contains(event.target)) {
show = false;
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
});
// Prevent menu from closing when clicked inside the menu element
menuElement.addEventListener("click", function (event) {
event.stopPropagation();
});
// Calculate half of the targetElement width
const targetHalfWidth = targetElement.offsetWidth / 2;
// Set a CSS variable with the half width value
targetElement.style.setProperty(
"--target-half-width",
targetHalfWidth + "px"
);
}
目前,我面临的问题是,单击时选择元素无法打开,但在使用回车键和向上/向下按钮时,它确实可以正常工作。
我怀疑问题可能与 event.stopPropagation() 函数有关,因为当我删除该行时,会添加 select 元素的“open”类(如检查工具所示)。但是,删除 event.stopPropagation() 行也会导致下拉菜单立即关闭。
我的目标是找到一种解决方案,允许我在不关闭下拉菜单的情况下打开选择元素。我将不胜感激关于如何实现这一目标的任何见解或建议。
以下是相关的HTML代码(html文件代码)供参考。感谢您的帮助!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
id="hello-elementor-child-style-css"
href="https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3"
media="all"
/>
<link rel="stylesheet" href="header.css" />
<script src="header.js" defer></script>
<!-- single-menu dropdown style -->
<link rel="stylesheet" href="single-menu-dropdown.css" />
<!-- custom form element style (nice-select) -->
<link rel="stylesheet" href="form.css" />
<!-- nice-select style-->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css"
integrity="sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>Header</title>
</head>
<body>
<header class="header HruDj">
<div class="nav-dropdown target-id DeYlt" id="target_id1">
<p>toggle dropdown</p>
<!-- single-menu dropdown container -->
<div id="menu_id1" class="menu-id">
<div class="form-field full-width">
<input
type="hidden"
name="form_my_contact_form"
value="1"
/>
<label for="product_type">Product Type</label>
<select
name="product_type"
id="product_type"
required=""
>
<option value="book">Book</option>
<option value="movie">Movie</option>
<option value="music">Music</option>
<option value="" disabled="">
Select a product type
</option>
</select>
</div>
</div>
</div>
<div class="nav-dropdown target-id DeYlt" id="target_id2">
<p>toggle dropdown</p>
<!-- single-menu dropdown container -->
<div id="menu_id2" class="menu-id">
<div class="form-field full-width">
<input
type="hidden"
name="form_my_contact_form"
value="1"
/>
<label for="product_type">Product Type</label>
<select
name="product_type"
id="product_type"
required=""
>
<option value="book">Book</option>
<option value="movie">Movie</option>
<option value="music">Music</option>
<option value="" disabled="">
Select a product type
</option>
</select>
</div>
</div>
</div>
</div>
</header>
<!-- jquery cdn -->
<script src="popup/jquery/jquery.min.js"></script>
<!-- single-menu dropdown script -->
<script src="single-menu-dropdown.js"></script>
<!-- nice-select script -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/js/jquery.nice-select.min.js"
integrity="sha512-NqYds8su6jivy1/WLoW8x1tZMRD7/1ZfhWG/jcRQLOzV1k1rIODCpMgoBnar5QXshKJGV7vi0LXLNXPoFsM5Zg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<!-- initialize dropdown and select -->
<script>
// Call singleMenu function for each menu
singleMenu("target_id1", "menu_id1", false);
singleMenu("target_id2", "menu_id2", false);
$(document).ready(function () {
// Apply the niceSelect plugin to all select elements
$("select").niceSelect();
});
</script>
</body>
</html>
答:
我很确定这只是由于事件传播顺序而发生的。单击时,这就是我所看到的:select
- 上的 click 事件触发该函数。
select
niceSelect
- 然后,click 事件会冒泡到父元素,最终到达 your 并在添加 .
menuElement
event.stopPropagation()
我相信这是一个问题的原因是因为它不会在单击时立即解决,并且它会在执行其操作之前等待下一个事件循环。但是,由于事件发生之前,就已经发生了,因此请阻止这种情况发生。niceSelect
stopPropagation()
stopPropagation()
解决此问题的一种可能非正统的方法是像这样延迟您的停止:stopPropagation()
menuElement.addEventListener("click", function (event) {
setTimeout(() => event.stopPropagation(), 0);
});
通俗地说,这告诉 javascript“在事件循环完成后立即运行此代码,但在下一个循环开始之前”。
将事件侦听器添加到 时,尝试通过提供第三个属性 来指定 useCapture
。所以它在 的 click 事件之前触发:targetElement
true
true
menuElement
// Toggle menu visibility when target element is clicked
targetElement.addEventListener('click', () => {
show = !show;
if (show) {
// show dropdown
menuElement.style.display = 'block';
targetElement.classList.add('active');
} else {
// hide dropdown
menuElement.style.display = 'none';
targetElement.classList.remove('active');
}
}, true); // set useCapture to true
因此,我能够达到预期的结果,但进行了一些小的更改。
似乎没有任何方法可以始终如一地工作。event.stopPropagation()
您可以做的是,与其将整个菜单父级设置为单击处理程序,不如将其设置为在更直接的目标上工作。
这意味着,而不是使用
<div class="nav-dropdown target-id DeYlt" id="target_id1">
<p>toggle dropdown</p>
您可能希望将目标 ID 添加到里面的 p 标签中。
<div class="nav-dropdown target-id DeYlt">
<p id="target_id1">toggle dropdown</p>
menu_id2和target_id2也是如此。
这将需要对 javascript 进行一些小的更改。
更改在单击外部处理时关闭菜单的单击处理程序,而不是考虑目标现在在菜单内。targetElement.parentElement
// Close menu if clicked outside of container
document.addEventListener("click", (event) => {
if (!targetElement.parentElement.contains(event.target)) {
show = false;
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
});
删除菜单停止传播项,因为它不再需要。
menuElement.addEventListener("click", function (event) {
event.stopPropagation();
总而言之,这是您的问题中的更新代码的样子,它应该按预期工作。
function singleMenu(targetId, menuId, show = false) {
const targetElement = document.getElementById(targetId);
const menuElement = document.getElementById(menuId);
// Initial state
if (show) {
// show dropdown
menuElement.style.display = "block";
targetElement.classList.add("active");
} else {
// hide dropdown
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
// Toggle menu visibility when target element is clicked
targetElement.addEventListener("click", () => {
show = !show;
if (show) {
// show dropdown
menuElement.style.display = "block";
targetElement.classList.add("active");
} else {
// hide dropdown
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
});
// Close menu if clicked outside of container
document.addEventListener("click", (event) => {
if (!targetElement.parentElement.contains(event.target)) {
show = false;
menuElement.style.display = "none";
targetElement.classList.remove("active");
}
});
// Prevent menu from closing when clicked inside the menu element
/* menuElement.addEventListener("click", function (event) {
event.stopPropagation();
});*/
// Calculate half of the targetElement width
const targetHalfWidth = targetElement.offsetWidth / 2;
// Set a CSS variable with the half width value
targetElement.style.setProperty(
"--target-half-width",
targetHalfWidth + "px"
);
}
singleMenu("target_id1", "menu_id1", false);
singleMenu("target_id2", "menu_id2", false);
$(document).ready(function () {
// Apply the niceSelect plugin to all select elements
$("select").niceSelect();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
id="hello-elementor-child-style-css"
href="https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3"
media="all"
/>
<link rel="stylesheet" href="header.css" />
<script src="header.js" defer></script>
<!-- single-menu dropdown style -->
<link rel="stylesheet" href="single-menu-dropdown.css" />
<!-- custom form element style (nice-select) -->
<link rel="stylesheet" href="form.css" />
<!-- nice-select style-->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css"
integrity="sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>Header</title>
</head>
<body>
<header class="header HruDj">
<div class="nav-dropdown target-id DeYlt">
<p id="target_id1">toggle dropdown</p>
<!-- single-menu dropdown container -->
<div id="menu_id1" class="menu-id">
<div class="form-field full-width">
<input
type="hidden"
name="form_my_contact_form"
value="1"
/>
<label for="product_type">Product Type</label>
<select
name="product_type"
id="product_type"
required=""
>
<option value="book">Book</option>
<option value="movie">Movie</option>
<option value="music">Music</option>
<option value="" disabled="">
Select a product type
</option>
</select>
</div>
</div>
</div>
<div class="nav-dropdown target-id DeYlt">
<p id="target_id2">toggle dropdown</p>
<!-- single-menu dropdown container -->
<div id="menu_id2" class="menu-id">
<div class="form-field full-width">
<input
type="hidden"
name="form_my_contact_form"
value="1"
/>
<label for="product_type">Product Type</label>
<select
name="product_type"
id="product_type"
required=""
>
<option value="book">Book</option>
<option value="movie">Movie</option>
<option value="music">Music</option>
<option value="" disabled="">
Select a product type
</option>
</select>
</div>
</div>
</div>
</div>
</header>
<!-- jquery cdn -->
<script src="popup/jquery/jquery.min.js"></script>
<!-- single-menu dropdown script -->
<script src="single-menu-dropdown.js"></script>
<!-- nice-select script -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/js/jquery.nice-select.min.js"
integrity="sha512-NqYds8su6jivy1/WLoW8x1tZMRD7/1ZfhWG/jcRQLOzV1k1rIODCpMgoBnar5QXshKJGV7vi0LXLNXPoFsM5Zg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<!-- initialize dropdown and select -->
<script>
// Call singleMenu function for each menu
</script>
</body>
</html>
注意:将以下代码移至 javascript 部分只是为了使代码片段可运行,这不是必需的修改。
singleMenu("target_id1", "menu_id1", false);
singleMenu("target_id2", "menu_id2", false);
$(document).ready(function () {
// Apply the niceSelect plugin to all select elements
$("select").niceSelect();
});
评论