javascript 父元素的事件阻止了子元素的click事件,stopPropagation

sqyvllje  于 2023-08-02  发布在  Java
关注(0)|答案(3)|浏览(196)

在我的(live site)上,我使用'nice-select'库创建了一个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"
    );
}

字符串
目前,我面临着一个问题,选择元素在单击时无法打开,但在使用enter和up/down按钮时可以正常工作。
我怀疑这个问题可能与event.stopPropagation()函数有关,因为当我删除该行时,会添加select元素的'open'类(如inspect工具中所示)。但是,删除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>

hkmswyz6

hkmswyz61#

所以我能够达到预期的结果,但有一些小的变化。对于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();
 });

hfyxw5xn

hfyxw5xn2#

我很确定这只是因为事件传播顺序而发生的。当点击select时,这就是我看到的情况:

  1. select上的click事件触发niceSelect函数。
    1.然后click事件冒泡到父元素,最终到达menuElement,并在添加event.stopPropagation()后停止。
    我认为这是一个问题的原因是因为niceSelect在单击时不会立即解析,它在执行其操作之前等待下一个事件循环。但是由于事件在此之前就已经命中了stopPropagation(),因此stopPropagation()阻止了此事件的发生。
    解决这个问题的一个可能的非正统方法是延迟您在stopPropagation()上的止损,如下所示:
menuElement.addEventListener("click", function (event) {
  setTimeout(() => event.stopPropagation(), 0);
});

字符串
通俗地说,这告诉JavaScript “在事件循环结束后,但在下一个循环开始之前,立即运行此代码”

eqqqjvef

eqqqjvef3#

在将事件侦听器添加到targetElement时,尝试通过提供第三个属性trueuseCapture指定为true。所以它在menuElement的click事件之前触发:

// 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

字符串

相关问题