事件委托的问题

Trouble with event delegation

我正在使用 mapbox geocoder 插件,它是一个搜索栏,可在您键入并在下拉列表中显示时填充地点建议。本质上,我正在使用动态列表元素。我正在尝试使用事件委托,所以当我单击列表项时,我创建的函数被触发。

我的功能没有任何问题,因为我正在其他地方使用它。我决定尝试 console.log("Li has been clicked!!") 来验证列表项是否在识别我的 'click'。事实并非如此,控制台中也没有抛出任何错误。所以我不确定到底出了什么问题。

下面是动态生成的 html 片段以及我对事件委托的尝试。任何帮助识别错误的帮助将不胜感激。谢谢。

HTML:

<div class="suggestions-wrapper">
    <ul class="suggestions" style="display: none;">
        <li class=" active">
            <a>
                <div class="mapboxgl-ctrl-geocoder--suggestion">
                    <div class="mapboxgl-ctrl-geocoder--suggestion-title">844 Napa Valley Drive</div>
                    <div class="mapboxgl-ctrl-geocoder--suggestion-address"> Fort Collins, Colorado 80525, United States of America</div>
                </div>
            </a>
        </li>
        <li>
            <a>
                <div class="mapboxgl-ctrl-geocoder--suggestion">
                    <div class="mapboxgl-ctrl-geocoder--suggestion-title">844 Courtenay Circle</div>
                    <div class="mapboxgl-ctrl-geocoder--suggestion-address"> Fort Collins, Colorado 80525, United States of America</div>
                </div>
            </a>
        </li>
    </ul>
</div>

JS:

document.getElementsByClassName('suggestions')[0].addEventListener('click', function(e) {
    if(e.target && e.target.nodeName == "LI") {
        plotIso();
        console.log("Li has been clicked!!")
    }
})

解法:

我在我的应用程序中将 'click' 更改为 'mouseup',并且还按照 @Menelaos Bakopoulos 的建议将 'LI' 更改为 'DIV'。不确定为什么它接受 'mouseup' 而不是 'click'。我假设它与 mapbox geocode 插件的编码方式有关。

var searchSugg = document.getElementsByClassName('suggestions')[0];
searchSugg.addEventListener('mouseup', function(e) {
    if(e.target && e.target.nodeName == "DIV") {
        plotIso();
        console.log("Li has been clicked!!")
    }
});

将条件放在 "LI" 上意味着您必须单击实际的点。 如果您不单击项目符号或点,则什么也不会发生。

您需要更改此条件。

我注释掉了你的 IF 语句,这确实显示了我添加的 console.log 和警报。

document.getElementsByClassName('suggestions')[0].addEventListener('click', function(e) {
    //if(e.target && e.target.nodeName == "LI") {
       alert("Li has been clicked!!")
        console.log("Li has been clicked!!")
   // }
})

Fiddle: https://jsfiddle.net/menelaosbgr/ftbpyLr9/3/

更新

如 OP 所述,将 LI 更改为 DIV 可解决问题:

 document.getElementsByClassName('suggestions')[0].addEventListener('click', function(e) {
        //if(e.target && e.target.nodeName == "DIV") {
           alert("Li has been clicked!!")
            console.log("Li has been clicked!!")
       // }
    })

因为您不一定要点击 DOT or BULLET of LI,您可以点击 a>, div> ( li的孩子>)。所以条件 e.target.nodeName == "LI" 不够好。我向您推荐以下代码段:

function findClosest(el, selector) {
    if (!Element.prototype.closest) { // Older browsers
        let e = el;
        while (e) {
            if (selectorMatches(e, selector)) {
                return e;
            }
            e = e.parentElement;
        }
    }
    // Modern browsers
    return el.closest(selector);
}

document.getElementsByClassName('suggestions')[0].addEventListener('click', function(e) {
    let ele = e.target; // ele is always available here because the event click is fired
    let liClicked = findClosest(ele, 'li'); // get enclosed <LI> of ele clicked
    if(liClicked) {
        plotIso();
        console.log("Li has been clicked!!", liClicked);
    }
})