You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

event.stopPropagation()失效:点击搜索建议项时列表自动关闭求助

搜索建议列表点击行为修复方案

问题描述

实现了搜索功能:用户在搜索框输入内容时显示字符建议列表,每个列表项包含字符名称(可跳转)和收藏图标。当前问题:点击任意<li>项或心形图标时,suggestionsList会自动关闭,不符合预期。预期效果:

  • 点击字符名称:跳转至目标页面
  • 点击收藏图标:调用关联函数完成收藏/取消操作,且suggestionsList保持打开状态
  • 仅点击列表外部时,才关闭suggestionsList
    已尝试event.stopPropagation()但未生效,需用原生JS解决。

原始代码

HTML

<div class="search-container">
    <input class="input" type="text" id="searchInput" placeholder="Type to search">
    <ul class="suggestions" id="suggestionsList">
        
    </ul>
</div>

JS

searchInput.addEventListener('input', () => {
    let userInput = searchInput.value.toLowerCase();
    let filterSuggestion = heroList.filter((char) => char.name.toLowerCase().startsWith(userInput));
    displaySuggestionList(filterSuggestion);
});

function displaySuggestionList(suggestion) {
    suggestionsList.innerHTML = '';
    if (suggestion.length > 0) {
        suggestion.forEach((char) => {
            let searchDiv = `
                <li data-index=${char.id} >
                    <a href="#"> ${char.name} </a>
                    <i class="fa-heart 
                        ${ 
                            favList ? 
                            favList.includes(char.id) ? 'fa-solid' : 'fa-regular' 
                            : 'fa-regular'
                        }
                    "></i>
                </li>`;
            suggestionsList.insertAdjacentHTML('beforeEnd', searchDiv);
        });

        // Add event listener to suggestionsList to prevent automatic closure
        suggestionsList.addEventListener('click', (event) => {
            event.stopPropagation();
        });

        // Add event listeners to <li> elements
        suggestionsList.querySelectorAll('li').forEach((li) => {
            li.addEventListener('click', () => {
                // Call the clickFav function with the corresponding data-index
                clickFav();
            });
        });

    } else {
        suggestionsList.innerHTML = '<li>No suggestions found</li>';
    }
}

function clickFav(event) {
    if (event.target.classList.contains('fa-heart')) {
        const id = event.target.parentElement.dataset.index;
        createFavAndLocal(id,event);
    }
}

问题根源分析

  1. 重复绑定事件:每次调用displaySuggestionList都会给suggestionsList新增一个click监听,导致事件处理逻辑混乱,stopPropagation无法正常生效。
  2. 事件传递错误:li的点击监听未传递event参数,导致clickFav无法获取点击目标,且点击li时会触发不必要的逻辑。
  3. 事件冒泡未精准拦截:未区分点击目标(名称/图标),统一阻止冒泡会影响正常跳转,且未阻止可能导致列表关闭的外部事件(比如document上的点击关闭逻辑)。

修复后的代码

JS部分

// 初始化时仅绑定一次suggestionsList的点击事件,用事件委托处理
suggestionsList.addEventListener('click', (event) => {
    event.stopPropagation(); // 阻止事件冒泡到外部,避免触发列表关闭逻辑
    const target = event.target;

    // 点击收藏图标时处理
    if (target.classList.contains('fa-heart')) {
        const id = target.parentElement.dataset.index;
        createFavAndLocal(id, event);
        // 直接切换图标状态,避免重新渲染整个列表
        target.classList.toggle('fa-solid');
        target.classList.toggle('fa-regular');
        return;
    }

    // 点击名称链接时,允许默认跳转行为,可替换为实际跳转地址
    if (target.tagName === 'A') {
        target.href = `/hero/${target.parentElement.dataset.index}`;
        return;
    }
});

searchInput.addEventListener('input', () => {
    let userInput = searchInput.value.toLowerCase();
    let filterSuggestion = heroList.filter((char) => char.name.toLowerCase().startsWith(userInput));
    displaySuggestionList(filterSuggestion);
});

function displaySuggestionList(suggestion) {
    suggestionsList.innerHTML = '';
    if (suggestion.length > 0) {
        suggestion.forEach((char) => {
            let searchDiv = `
                <li data-index=${char.id} >
                    <a href="#"> ${char.name} </a>
                    <i class="fa-heart 
                        ${ 
                            favList && favList.includes(char.id) ? 'fa-solid' : 'fa-regular'
                        }
                    "></i>
                </li>`;
            suggestionsList.insertAdjacentHTML('beforeEnd', searchDiv);
        });
    } else {
        suggestionsList.innerHTML = '<li>No suggestions found</li>';
    }
}

function createFavAndLocal(id, event) {
    // 收藏逻辑示例:更新本地列表与本地存储
    if (favList.includes(id)) {
        favList = favList.filter(item => item !== id);
    } else {
        favList.push(id);
    }
    localStorage.setItem('favList', JSON.stringify(favList));
}

外部点击关闭列表的补充逻辑

确保关闭列表的逻辑仅在点击搜索容器外部时触发:

document.addEventListener('click', (event) => {
    const searchContainer = document.querySelector('.search-container');
    if (!searchContainer.contains(event.target)) {
        suggestionsList.style.display = 'none';
    }
});

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 00:09:56