子元素的点击事件被父元素的 event.stopPropagation 阻止了。

huangapple go评论91阅读模式
英文:

Child element's click event prevented by parent's event.stopPropagation

问题

在我的[线上网站][1]上,我使用了 'nice-select' 库创建了一个选择元素。这个选择元素嵌套在一个下拉菜单中,该菜单有自己的JavaScript文件。

  1. function singleMenu(targetId, menuId, show = false) {
  2. const targetElement = document.getElementById(targetId);
  3. const menuElement = document.getElementById(menuId);
  4. // 初始状态
  5. if (show) {
  6. // 显示下拉菜单
  7. menuElement.style.display = "block";
  8. targetElement.classList.add("active");
  9. } else {
  10. // 隐藏下拉菜单
  11. menuElement.style.display = "none";
  12. targetElement.classList.remove("active");
  13. }
  14. // 当点击目标元素时切换菜单可见性
  15. targetElement.addEventListener("click", () => {
  16. show = !show;
  17. if (show) {
  18. // 显示下拉菜单
  19. menuElement.style.display = "block";
  20. targetElement.classList.add("active");
  21. } else {
  22. // 隐藏下拉菜单
  23. menuElement.style.display = "none";
  24. targetElement.classList.remove("active");
  25. }
  26. });
  27. // 如果在容器外部点击,关闭菜单
  28. document.addEventListener("click", (event) => {
  29. if (!targetElement.contains(event.target)) {
  30. show = false;
  31. menuElement.style.display = "none";
  32. targetElement.classList.remove("active");
  33. }
  34. });
  35. // 防止点击菜单元素内部时关闭菜单
  36. menuElement.addEventListener("click", function (event) {
  37. event.stopPropagation();
  38. });
  39. // 计算目标元素宽度的一半
  40. const targetHalfWidth = targetElement.offsetWidth / 2;
  41. // 使用一半宽度值设置CSS变量
  42. targetElement.style.setProperty(
  43. "--target-half-width",
  44. targetHalfWidth + "px"
  45. );
  46. }

目前,我面临一个问题,即当单击选择元素时,它不会打开,但使用回车键和上/下箭头按钮时它可以正常工作。

我怀疑问题可能与 event.stopPropagation() 函数有关,因为当我删除该行时,选择元素的 'open' 类会添加(在检查工具中可见)。然而,删除 event.stopPropagation() 行也会导致下拉菜单立即关闭。

我的目标是找到一种解决方案,允许我打开选择元素而不关闭下拉菜单。非常感谢您对如何实现这一目标的任何见解或建议。

以下是相关的HTML代码(HTML文件代码)以供参考。谢谢您的帮助!

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <link
  7. rel="stylesheet"
  8. id="hello-elementor-child-style-css"
  9. href="https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3"
  10. media="all"
  11. />
  12. <link rel="stylesheet" href="header.css" />
  13. <script src="header.js" defer></script>
  14. <!-- single-menu dropdown style -->
  15. <link rel="stylesheet" href="single-menu-dropdown.css" />
  16. <!-- custom form element style (nice-select) -->
  17. <link rel="stylesheet" href="form.css" />
  18. <!-- nice-select style-->
  19. <link
  20. rel="stylesheet"
  21. href="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css"
  22. integrity="sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ=="
  23. crossorigin="anonymous"
  24. referrerpolicy="no-referrer"
  25. />
  26. <title>Header</title>
  27. </head>
  28. <body>
  29. <header class="header HruDj">
  30. <div class="nav-dropdown target-id DeYlt" id="target_id1">
  31. <p>toggle dropdown</p>
  32. <!-- single-menu dropdown container -->
  33. <div id="menu_id1" class="menu-id">
  34. <div class="form-field full-width">
  35. <input
  36. type="hidden"
  37. name="form_my_contact_form"
  38. value="1"
  39. />
  40. <label for="product_type">Product Type</label>
  41. <select
  42. name="product_type"
  43. id="product_type"
  44. required=""
  45. >
  46. <option value="book">Book</option>
  47. <option value="movie">Movie</option>
  48. <option value="music">Music</option>
  49. <option value="" disabled="">
  50. Select a product type
  51. </option>
  52. </select>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="nav-dropdown target-id DeYlt" id="target_id2">
  57. <p>toggle dropdown</p>
  58. <!-- single-menu dropdown container -->
  59. <div id="menu_id2" class="menu-id">
  60. <div class="form-field full-width">
  61. <input
  62. type="hidden"
  63. name="form_my_contact_form"
  64. value="1"
  65. />
  66. <label for="product_type">Product Type</label>
  67. <select
  68. name="product_type"
  69. id="product_type"
  70. required=""
  71. >
  72. <option value="book">Book</option>
  73. <option value="movie">Movie</option>
  74. <option value="music">Music</option>
  75. <option value="" disabled="">
  76. Select a product type
  77. </option>
  78. </select>
  79. </div>
  80. </div>
  81. </div>
  82. </header>
  83. <!-- jquery cdn -->
  84. <script src="popup/jquery/jquery.min.js"></script>
  85. <!-- single-menu dropdown script -->
  86. <script src="single-menu-dropdown.js"></script>
  87. <!-- nice-select script -->
  88. <script
  89. src="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/js/jquery.nice-select.min.js"
  90. integrity="sha512-NqYds8su6jivy1/WLoW8x1tZMRD7/1ZfhWG/jcRQLOzV1k1rIODCpMgoBnar5QXshKJGV7vi0LXLNXPoFsM5Zg=="
  91. crossorigin="anonymous"
  92. referrerpolicy="no-referrer"
  93. ></script>
  94. <!-- initialize dropdown and select -->
  95. <script>
  96. // 为每个菜单调用singleMenu函数
  97. singleMenu("target_id1", "menu_id1
  98. <details>
  99. <summary>英文:</summary>
  100. On my ([live site][1]), I have a select element created using the &#39;nice-select&#39; library. This select element is nested inside a dropdown menu, which has its own JavaScript file
  101. function singleMenu(targetId, menuId, show = false) {
  102. const targetElement = document.getElementById(targetId);
  103. const menuElement = document.getElementById(menuId);
  104. // Initial state
  105. if (show) {
  106. // show dropdown
  107. menuElement.style.display = &quot;block&quot;;
  108. targetElement.classList.add(&quot;active&quot;);
  109. } else {
  110. // hide dropdown
  111. menuElement.style.display = &quot;none&quot;;
  112. targetElement.classList.remove(&quot;active&quot;);
  113. }
  114. // Toggle menu visibility when target element is clicked
  115. targetElement.addEventListener(&quot;click&quot;, () =&gt; {
  116. show = !show;
  117. if (show) {
  118. // show dropdown
  119. menuElement.style.display = &quot;block&quot;;
  120. targetElement.classList.add(&quot;active&quot;);
  121. } else {
  122. // hide dropdown
  123. menuElement.style.display = &quot;none&quot;;
  124. targetElement.classList.remove(&quot;active&quot;);
  125. }
  126. });
  127. // Close menu if clicked outside of container
  128. document.addEventListener(&quot;click&quot;, (event) =&gt; {
  129. if (!targetElement.contains(event.target)) {
  130. show = false;
  131. menuElement.style.display = &quot;none&quot;;
  132. targetElement.classList.remove(&quot;active&quot;);
  133. }
  134. });
  135. // Prevent menu from closing when clicked inside the menu element
  136. menuElement.addEventListener(&quot;click&quot;, function (event) {
  137. event.stopPropagation();
  138. });
  139. // Calculate half of the targetElement width
  140. const targetHalfWidth = targetElement.offsetWidth / 2;
  141. // Set a CSS variable with the half width value
  142. targetElement.style.setProperty(
  143. &quot;--target-half-width&quot;,
  144. targetHalfWidth + &quot;px&quot;
  145. );
  146. }
  147. Currently, I&#39;m facing an issue where the select element does not open when clicked, but it does work properly when using the enter and up/down buttons.
  148. I suspect that the problem might be related to the event.stopPropagation() function, as when I remove that line, the select element&#39;s &#39;open&#39; class gets added (as seen in the inspect tool). However, removing the event.stopPropagation() line also results in the dropdown menu closing immediately.
  149. My goal is to find a solution that allows me to open the select elements without closing the dropdown menu. I would greatly appreciate any insights or suggestions on how to achieve this.
  150. Here is the relevant HTML code (html file code) for reference. Thank you for your help!
  151. &lt;!DOCTYPE html&gt;
  152. &lt;html lang=&quot;en&quot;&gt;
  153. &lt;head&gt;
  154. &lt;meta charset=&quot;UTF-8&quot; /&gt;
  155. &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
  156. &lt;link
  157. rel=&quot;stylesheet&quot;
  158. id=&quot;hello-elementor-child-style-css&quot;
  159. href=&quot;https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3&quot;
  160. media=&quot;all&quot;
  161. /&gt;
  162. &lt;link rel=&quot;stylesheet&quot; href=&quot;header.css&quot; /&gt;
  163. &lt;script src=&quot;header.js&quot; defer&gt;&lt;/script&gt;
  164. &lt;!-- single-menu dropdown style --&gt;
  165. &lt;link rel=&quot;stylesheet&quot; href=&quot;single-menu-dropdown.css&quot; /&gt;
  166. &lt;!-- custom form element style (nice-select) --&gt;
  167. &lt;link rel=&quot;stylesheet&quot; href=&quot;form.css&quot; /&gt;
  168. &lt;!-- nice-select style--&gt;
  169. &lt;link
  170. rel=&quot;stylesheet&quot;
  171. href=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css&quot;
  172. integrity=&quot;sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ==&quot;
  173. crossorigin=&quot;anonymous&quot;
  174. referrerpolicy=&quot;no-referrer&quot;
  175. /&gt;
  176. &lt;title&gt;Header&lt;/title&gt;
  177. &lt;/head&gt;
  178. &lt;body&gt;
  179. &lt;header class=&quot;header HruDj&quot;&gt;
  180. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot; id=&quot;target_id1&quot;&gt;
  181. &lt;p&gt;toggle dropdown&lt;/p&gt;
  182. &lt;!-- single-menu dropdown container --&gt;
  183. &lt;div id=&quot;menu_id1&quot; class=&quot;menu-id&quot;&gt;
  184. &lt;div class=&quot;form-field full-width&quot;&gt;
  185. &lt;input
  186. type=&quot;hidden&quot;
  187. name=&quot;form_my_contact_form&quot;
  188. value=&quot;1&quot;
  189. /&gt;
  190. &lt;label for=&quot;product_type&quot;&gt;Product Type&lt;/label&gt;
  191. &lt;select
  192. name=&quot;product_type&quot;
  193. id=&quot;product_type&quot;
  194. required=&quot;&quot;
  195. &gt;
  196. &lt;option value=&quot;book&quot;&gt;Book&lt;/option&gt;
  197. &lt;option value=&quot;movie&quot;&gt;Movie&lt;/option&gt;
  198. &lt;option value=&quot;music&quot;&gt;Music&lt;/option&gt;
  199. &lt;option value=&quot;&quot; disabled=&quot;&quot;&gt;
  200. Select a product type
  201. &lt;/option&gt;
  202. &lt;/select&gt;
  203. &lt;/div&gt;
  204. &lt;/div&gt;
  205. &lt;/div&gt;
  206. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot; id=&quot;target_id2&quot;&gt;
  207. &lt;p&gt;toggle dropdown&lt;/p&gt;
  208. &lt;!-- single-menu dropdown container --&gt;
  209. &lt;div id=&quot;menu_id2&quot; class=&quot;menu-id&quot;&gt;
  210. &lt;div class=&quot;form-field full-width&quot;&gt;
  211. &lt;input
  212. type=&quot;hidden&quot;
  213. name=&quot;form_my_contact_form&quot;
  214. value=&quot;1&quot;
  215. /&gt;
  216. &lt;label for=&quot;product_type&quot;&gt;Product Type&lt;/label&gt;
  217. &lt;select
  218. name=&quot;product_type&quot;
  219. id=&quot;product_type&quot;
  220. required=&quot;&quot;
  221. &gt;
  222. &lt;option value=&quot;book&quot;&gt;Book&lt;/option&gt;
  223. &lt;option value=&quot;movie&quot;&gt;Movie&lt;/option&gt;
  224. &lt;option value=&quot;music&quot;&gt;Music&lt;/option&gt;
  225. &lt;option value=&quot;&quot; disabled=&quot;&quot;&gt;
  226. Select a product type
  227. &lt;/option&gt;
  228. &lt;/select&gt;
  229. &lt;/div&gt;
  230. &lt;/div&gt;
  231. &lt;/div&gt;
  232. &lt;/div&gt;
  233. &lt;/header&gt;
  234. &lt;!-- jquery cdn --&gt;
  235. &lt;script src=&quot;popup/jquery/jquery.min.js&quot;&gt;&lt;/script&gt;
  236. &lt;!-- single-menu dropdown script --&gt;
  237. &lt;script src=&quot;single-menu-dropdown.js&quot;&gt;&lt;/script&gt;
  238. &lt;!-- nice-select script --&gt;
  239. &lt;script
  240. src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/js/jquery.nice-select.min.js&quot;
  241. integrity=&quot;sha512-NqYds8su6jivy1/WLoW8x1tZMRD7/1ZfhWG/jcRQLOzV1k1rIODCpMgoBnar5QXshKJGV7vi0LXLNXPoFsM5Zg==&quot;
  242. crossorigin=&quot;anonymous&quot;
  243. referrerpolicy=&quot;no-referrer&quot;
  244. &gt;&lt;/script&gt;
  245. &lt;!-- initialize dropdown and select --&gt;
  246. &lt;script&gt;
  247. // Call singleMenu function for each menu
  248. singleMenu(&quot;target_id1&quot;, &quot;menu_id1&quot;, false);
  249. singleMenu(&quot;target_id2&quot;, &quot;menu_id2&quot;, false);
  250. $(document).ready(function () {
  251. // Apply the niceSelect plugin to all select elements
  252. $(&quot;select&quot;).niceSelect();
  253. });
  254. &lt;/script&gt;
  255. &lt;/body&gt;
  256. &lt;/html&gt;
  257. [1]: https://drougnov.github.io/dashobard-copy/header.html
  258. </details>
  259. # 答案1
  260. **得分**: 1
  261. 我相当确信这只是因为事件传播顺序而发生的。当单击 `select` 时,我看到以下事件发生:
  262. 1. 单击 `select` 触发了 `niceSelect` 函数。
  263. 2. 单击事件然后冒泡到父元素,最终到达您的 `menuElement` 并停在那里,因为您添加了 `event.stopPropagation()`。
  264. 我认为这是一个问题的原因是因为 `niceSelect` 在单击时并没有立即解决,它在执行其操作之前正在等待下一个事件循环。但由于事件在发生之前调用了 `stopPropagation()`,因此 `stopPropagation()` 阻止了这个操作的发生。
  265. 一个可能不正规的解决方法是延迟在 `stopPropagation()` 上的停止,如下所示:
  266. ```javascript
  267. menuElement.addEventListener("click", function (event) {
  268. setTimeout(() => event.stopPropagation(), 0);
  269. });

通俗地说,这告诉 JavaScript:“在事件循环完成后但在下一个事件循环开始之前运行此代码”。

英文:

I am pretty sure this is just happening because of the event propagation order. When select is clicked, this is what I am seeing is happening:

  1. The click event on select fires the niceSelect function.
  2. The click event then bubbles up to the parent elements, eventually reaching your menuElement and stopping there since you added event.stopPropagation().

I believe the reason this is an issue is because niceSelect does not immediately resolve on click, and it's waiting for the next event loop before it performs its actions. But since the event is hitting stopPropagation() before that ever happens, stopPropagation() stops this from ever happening.

A possibly unorthodox method to fix this would be to just delay your stop on stopPropagation() like so:

  1. menuElement.addEventListener(&quot;click&quot;, function (event) {
  2. setTimeout(() =&gt; event.stopPropagation(), 0);
  3. });

In layman's terms, this tells javascript "Run this code as soon as the event loop is finished but before the start of the next one".

答案2

得分: 1

所以我能够得到所需的结果,但需要进行一些小的更改。
使用event.stopPropagation()似乎没有一种方法可以始终正常工作。

你可以做的是,不要将整个菜单父元素设置为点击处理程序,而是设置它在更直接的目标上工作。

这意味着不要使用:

  1. <div class="nav-dropdown target-id DeYlt" id="target_id1">
  2. <p>toggle dropdown</p>

而是希望将目标id添加到p标签内部。

  1. <div class="nav-dropdown target-id DeYlt">
  2. <p id="target_id1">toggle dropdown</p>

对于menu_id2和target_id2也是一样的。

这将需要在javascript中进行小的更改。
更改关闭菜单的点击处理程序,以处理targetElement.parentElement,以便考虑目标现在位于菜单内部。

  1. // Close menu if clicked outside of container
  2. document.addEventListener("click", (event) => {
  3. if (!targetElement.parentElement.contains(event.target)) {
  4. show = false;
  5. menuElement.style.display = "none";
  6. targetElement.classList.remove("active");
  7. }
  8. });

不再需要menu stop propagation项。

  1. menuElement.addEventListener("click", function (event) {
  2. event.stopPropagation();
  3. });

总之,以下是来自你的问题的更新后的代码,应该按预期工作:

  1. <!-- begin snippet: js hide: false console: true babel: false -->
  2. <!-- language: lang-js -->
  3. function singleMenu(targetId, menuId, show = false) {
  4. const targetElement = document.getElementById(targetId);
  5. const menuElement = document.getElementById(menuId);
  6. // Initial state
  7. if (show) {
  8. // show dropdown
  9. menuElement.style.display = "block";
  10. targetElement.classList.add("active");
  11. } else {
  12. // hide dropdown
  13. menuElement.style.display = "none";
  14. targetElement.classList.remove("active");
  15. }
  16. // Toggle menu visibility when target element is clicked
  17. targetElement.addEventListener("click", () => {
  18. show = !show;
  19. if (show) {
  20. // show dropdown
  21. menuElement.style.display = "block";
  22. targetElement.classList.add("active");
  23. } else {
  24. // hide dropdown
  25. menuElement.style.display = "none";
  26. targetElement.classList.remove("active");
  27. }
  28. });
  29. // Close menu if clicked outside of container
  30. document.addEventListener("click", (event) => {
  31. if (!targetElement.parentElement.contains(event.target)) {
  32. show = false;
  33. menuElement.style.display = "none";
  34. targetElement.classList.remove("active");
  35. }
  36. });
  37. // Prevent menu from closing when clicked inside the menu element
  38. /* menuElement.addEventListener("click", function (event) {
  39. event.stopPropagation();
  40. }); */
  41. // Calculate half of the targetElement width
  42. const targetHalfWidth = targetElement.offsetWidth / 2;
  43. // Set a CSS variable with the half width value
  44. targetElement.style.setProperty(
  45. "--target-half-width",
  46. targetHalfWidth + "px"
  47. );
  48. }
  49. singleMenu("target_id1", "menu_id1", false);
  50. singleMenu("target_id2", "menu_id2", false);
  51. $(document).ready(function () {
  52. // Apply the niceSelect plugin to all select elements
  53. $("select").niceSelect();
  54. });
  55. <!-- language: lang-html -->
  56. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  57. <!DOCTYPE html>
  58. <html lang="en">
  59. <head>
  60. <meta charset="UTF-8" />
  61. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  62. <link
  63. rel="stylesheet"
  64. id="hello-elementor-child-style-css"
  65. href="https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3"
  66. media="all"
  67. />
  68. <link rel="stylesheet" href="header.css" />
  69. <script src="header.js" defer></script>
  70. <!-- single-menu dropdown style -->
  71. <link rel="stylesheet" href="single-menu-dropdown.css" />
  72. <!-- custom form element style (nice-select) -->
  73. <link rel="stylesheet" href="form.css" />
  74. <!-- nice-select style-->
  75. <link
  76. rel="stylesheet"
  77. href="https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css"
  78. integrity="sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ=="
  79. crossorigin="anonymous"
  80. referrerpolicy="no-referrer"
  81. />
  82. <title>Header</title>
  83. </head>
  84. <body>
  85. <header class="header HruDj">
  86. <div class="nav-dropdown target-id DeYlt">
  87. <p id="target_id1">toggle dropdown</p>
  88. <!-- single-menu dropdown container -->
  89. <div id="menu_id1" class="menu-id">
  90. <div class="form-field full-width">
  91. <input
  92. type="hidden"
  93. name="form_my_contact_form"
  94. value="1"
  95. />
  96. <label for="product_type">Product Type</label>
  97. <select
  98. name="product_type"
  99. id="product_type"
  100. required=""
  101. >
  102. <option value="book">Book</option>
  103. <option value="movie">Movie</option>
  104. <option value="music">Music</option>
  105. <option value="" disabled="">
  106. Select a product type
  107. </option>
  108. </select>
  109. </div>
  110. </div>
  111. </div>
  112. <div class="nav-dropdown target-id DeYlt">
  113. <p id="target_id2">toggle dropdown</p>
  114. <!-- single-menu dropdown container -->
  115. <div id="menu_id2" class="menu-id">
  116. <div class="form-field full-width">
  117. <input
  118. type="hidden"
  119. name="form_my_contact_form"
  120. value="1"
  121. />
  122. <label for="product_type">Product Type</label>
  123. <select
  124. name="product_type"
  125. id="product_type"
  126. required=""
  127. >
  128. <option value="book">Book</option>
  129. <option value="movie">Movie</option>
  130. <option value="music">Music</option>
  131. <option value="" disabled="">
  132. Select a product type
  133. </option>
  134. </select>
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. </header>
  140. <!-- jquery cdn -->
  141. <script src="popup/jquery/jquery.min.js"></script>
  142. <!-- single-menu dropdown script -->
  143. <script src="single-menu-dropdown.js"></script>
  144. <!-- nice-select script -->
  145. <script
  146. src="https://cdnjs.cloudflare
  147. <details>
  148. <summary>英文:</summary>
  149. So I was able to arrive at the desired result but with some small changes.
  150. There didn&#39;t seem to be any approach with the `event.stopPropagation()` that would work consistently.
  151. What you can do is that instead of setting the whole menu parent as the click handler set it to work on the more direct target instead.
  152. This means that instead of using
  153. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot; id=&quot;target_id1&quot;&gt;
  154. &lt;p&gt;toggle dropdown&lt;/p&gt;
  155. You would want to add the target id to the p tag inside.
  156. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot;&gt;
  157. &lt;p id=&quot;target_id1&quot;&gt;toggle dropdown&lt;/p&gt;
  158. Same for the menu_id2 and target_id2.
  159. This will require a small change in the javascript.
  160. Change the click handler that closes the menu when clicking outside to handle `targetElement.parentElement` instead to account for the target being within the menu now.
  161. // Close menu if clicked outside of container
  162. document.addEventListener(&quot;click&quot;, (event) =&gt; {
  163. if (!targetElement.parentElement.contains(event.target)) {
  164. show = false;
  165. menuElement.style.display = &quot;none&quot;;
  166. targetElement.classList.remove(&quot;active&quot;);
  167. }
  168. });
  169. Get rid of the menu stop propagation item as it&#39;s no longer needed.
  170. menuElement.addEventListener(&quot;click&quot;, function (event) {
  171. event.stopPropagation();
  172. All in all, here&#39;s what an updated code from your question looks like which should work as expected.
  173. &lt;!-- begin snippet: js hide: false console: true babel: false --&gt;
  174. &lt;!-- language: lang-js --&gt;
  175. function singleMenu(targetId, menuId, show = false) {
  176. const targetElement = document.getElementById(targetId);
  177. const menuElement = document.getElementById(menuId);
  178. // Initial state
  179. if (show) {
  180. // show dropdown
  181. menuElement.style.display = &quot;block&quot;;
  182. targetElement.classList.add(&quot;active&quot;);
  183. } else {
  184. // hide dropdown
  185. menuElement.style.display = &quot;none&quot;;
  186. targetElement.classList.remove(&quot;active&quot;);
  187. }
  188. // Toggle menu visibility when target element is clicked
  189. targetElement.addEventListener(&quot;click&quot;, () =&gt; {
  190. show = !show;
  191. if (show) {
  192. // show dropdown
  193. menuElement.style.display = &quot;block&quot;;
  194. targetElement.classList.add(&quot;active&quot;);
  195. } else {
  196. // hide dropdown
  197. menuElement.style.display = &quot;none&quot;;
  198. targetElement.classList.remove(&quot;active&quot;);
  199. }
  200. });
  201. // Close menu if clicked outside of container
  202. document.addEventListener(&quot;click&quot;, (event) =&gt; {
  203. if (!targetElement.parentElement.contains(event.target)) {
  204. show = false;
  205. menuElement.style.display = &quot;none&quot;;
  206. targetElement.classList.remove(&quot;active&quot;);
  207. }
  208. });
  209. // Prevent menu from closing when clicked inside the menu element
  210. /* menuElement.addEventListener(&quot;click&quot;, function (event) {
  211. event.stopPropagation();
  212. });*/
  213. // Calculate half of the targetElement width
  214. const targetHalfWidth = targetElement.offsetWidth / 2;
  215. // Set a CSS variable with the half width value
  216. targetElement.style.setProperty(
  217. &quot;--target-half-width&quot;,
  218. targetHalfWidth + &quot;px&quot;
  219. );
  220. }
  221. singleMenu(&quot;target_id1&quot;, &quot;menu_id1&quot;, false);
  222. singleMenu(&quot;target_id2&quot;, &quot;menu_id2&quot;, false);
  223. $(document).ready(function () {
  224. // Apply the niceSelect plugin to all select elements
  225. $(&quot;select&quot;).niceSelect();
  226. });
  227. &lt;!-- language: lang-html --&gt;
  228. &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;&gt;&lt;/script&gt;
  229. &lt;!DOCTYPE html&gt;
  230. &lt;html lang=&quot;en&quot;&gt;
  231. &lt;head&gt;
  232. &lt;meta charset=&quot;UTF-8&quot; /&gt;
  233. &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
  234. &lt;link
  235. rel=&quot;stylesheet&quot;
  236. id=&quot;hello-elementor-child-style-css&quot;
  237. href=&quot;https://fs.codelinden.com/wp-content/themes/hello-child/style.css?ver=3&quot;
  238. media=&quot;all&quot;
  239. /&gt;
  240. &lt;link rel=&quot;stylesheet&quot; href=&quot;header.css&quot; /&gt;
  241. &lt;script src=&quot;header.js&quot; defer&gt;&lt;/script&gt;
  242. &lt;!-- single-menu dropdown style --&gt;
  243. &lt;link rel=&quot;stylesheet&quot; href=&quot;single-menu-dropdown.css&quot; /&gt;
  244. &lt;!-- custom form element style (nice-select) --&gt;
  245. &lt;link rel=&quot;stylesheet&quot; href=&quot;form.css&quot; /&gt;
  246. &lt;!-- nice-select style--&gt;
  247. &lt;link
  248. rel=&quot;stylesheet&quot;
  249. href=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/css/nice-select.min.css&quot;
  250. integrity=&quot;sha512-CruCP+TD3yXzlvvijET8wV5WxxEh5H8P4cmz0RFbKK6FlZ2sYl3AEsKlLPHbniXKSrDdFewhbmBK5skbdsASbQ==&quot;
  251. crossorigin=&quot;anonymous&quot;
  252. referrerpolicy=&quot;no-referrer&quot;
  253. /&gt;
  254. &lt;title&gt;Header&lt;/title&gt;
  255. &lt;/head&gt;
  256. &lt;body&gt;
  257. &lt;header class=&quot;header HruDj&quot;&gt;
  258. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot;&gt;
  259. &lt;p id=&quot;target_id1&quot;&gt;toggle dropdown&lt;/p&gt;
  260. &lt;!-- single-menu dropdown container --&gt;
  261. &lt;div id=&quot;menu_id1&quot; class=&quot;menu-id&quot;&gt;
  262. &lt;div class=&quot;form-field full-width&quot;&gt;
  263. &lt;input
  264. type=&quot;hidden&quot;
  265. name=&quot;form_my_contact_form&quot;
  266. value=&quot;1&quot;
  267. /&gt;
  268. &lt;label for=&quot;product_type&quot;&gt;Product Type&lt;/label&gt;
  269. &lt;select
  270. name=&quot;product_type&quot;
  271. id=&quot;product_type&quot;
  272. required=&quot;&quot;
  273. &gt;
  274. &lt;option value=&quot;book&quot;&gt;Book&lt;/option&gt;
  275. &lt;option value=&quot;movie&quot;&gt;Movie&lt;/option&gt;
  276. &lt;option value=&quot;music&quot;&gt;Music&lt;/option&gt;
  277. &lt;option value=&quot;&quot; disabled=&quot;&quot;&gt;
  278. Select a product type
  279. &lt;/option&gt;
  280. &lt;/select&gt;
  281. &lt;/div&gt;
  282. &lt;/div&gt;
  283. &lt;/div&gt;
  284. &lt;div class=&quot;nav-dropdown target-id DeYlt&quot;&gt;
  285. &lt;p id=&quot;target_id2&quot;&gt;toggle dropdown&lt;/p&gt;
  286. &lt;!-- single-menu dropdown container --&gt;
  287. &lt;div id=&quot;menu_id2&quot; class=&quot;menu-id&quot;&gt;
  288. &lt;div class=&quot;form-field full-width&quot;&gt;
  289. &lt;input
  290. type=&quot;hidden&quot;
  291. name=&quot;form_my_contact_form&quot;
  292. value=&quot;1&quot;
  293. /&gt;
  294. &lt;label for=&quot;product_type&quot;&gt;Product Type&lt;/label&gt;
  295. &lt;select
  296. name=&quot;product_type&quot;
  297. id=&quot;product_type&quot;
  298. required=&quot;&quot;
  299. &gt;
  300. &lt;option value=&quot;book&quot;&gt;Book&lt;/option&gt;
  301. &lt;option value=&quot;movie&quot;&gt;Movie&lt;/option&gt;
  302. &lt;option value=&quot;music&quot;&gt;Music&lt;/option&gt;
  303. &lt;option value=&quot;&quot; disabled=&quot;&quot;&gt;
  304. Select a product type
  305. &lt;/option&gt;
  306. &lt;/select&gt;
  307. &lt;/div&gt;
  308. &lt;/div&gt;
  309. &lt;/div&gt;
  310. &lt;/div&gt;
  311. &lt;/header&gt;
  312. &lt;!-- jquery cdn --&gt;
  313. &lt;script src=&quot;popup/jquery/jquery.min.js&quot;&gt;&lt;/script&gt;
  314. &lt;!-- single-menu dropdown script --&gt;
  315. &lt;script src=&quot;single-menu-dropdown.js&quot;&gt;&lt;/script&gt;
  316. &lt;!-- nice-select script --&gt;
  317. &lt;script
  318. src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-nice-select/1.1.0/js/jquery.nice-select.min.js&quot;
  319. integrity=&quot;sha512-NqYds8su6jivy1/WLoW8x1tZMRD7/1ZfhWG/jcRQLOzV1k1rIODCpMgoBnar5QXshKJGV7vi0LXLNXPoFsM5Zg==&quot;
  320. crossorigin=&quot;anonymous&quot;
  321. referrerpolicy=&quot;no-referrer&quot;
  322. &gt;&lt;/script&gt;
  323. &lt;!-- initialize dropdown and select --&gt;
  324. &lt;script&gt;
  325. // Call singleMenu function for each menu
  326. &lt;/script&gt;
  327. &lt;/body&gt;
  328. &lt;/html&gt;
  329. &lt;!-- end snippet --&gt;
  330. Note: moved the following code to the javascript portion only to make the code snippet runnable, that is not a required modification.
  331. singleMenu(&quot;target_id1&quot;, &quot;menu_id1&quot;, false);
  332. singleMenu(&quot;target_id2&quot;, &quot;menu_id2&quot;, false);
  333. $(document).ready(function () {
  334. // Apply the niceSelect plugin to all select elements
  335. $(&quot;select&quot;).niceSelect();
  336. });
  337. </details>
  338. # 答案3
  339. **得分**: 0
  340. 添加事件监听器到 `targetElement` 时,尝试通过给第三个属性设置为 `true` 来指定 [`useCapture`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) 为 `true`。这样可以在 `menuElement` 的点击事件之前触发:
  341. ```javascript
  342. // 当目标元素被点击时切换菜单的可见性
  343. targetElement.addEventListener('click', () => {
  344. show = !show;
  345. if (show) {
  346. // 显示下拉菜单
  347. menuElement.style.display = 'block';
  348. targetElement.classList.add('active');
  349. } else {
  350. // 隐藏下拉菜单
  351. menuElement.style.display = 'none';
  352. targetElement.classList.remove('active');
  353. }
  354. }, true); // 将 useCapture 设置为 true
英文:

When adding event listener to targetElement, try specifying useCapture to true by giving a third property of true. So it triggers before menuElement's click event:

  1. // Toggle menu visibility when target element is clicked
  2. targetElement.addEventListener(&#39;click&#39;, () =&gt; {
  3. show = !show;
  4. if (show) {
  5. // show dropdown
  6. menuElement.style.display = &#39;block&#39;;
  7. targetElement.classList.add(&#39;active&#39;);
  8. } else {
  9. // hide dropdown
  10. menuElement.style.display = &#39;none&#39;;
  11. targetElement.classList.remove(&#39;active&#39;);
  12. }
  13. }, true); // set useCapture to true

huangapple
  • 本文由 发表于 2023年7月20日 14:31:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76727233.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定