首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

AJAX 搜尋建議下拉框自動關閉問題解決:滑鼠點擊外部隱藏完整方案

     編輯:PHP 相關知識

前言

實作 Google 風格搜尋建議時,常遇到「點擊輸入框外部區域,建議下拉框不自動關閉」的體驗問題。本文提供原生 JavaScript 完整解決方案,並分析事件流機制。

問題重現

原始碼中:

  • onblur="losefouse()" 綁定在輸入框,當焦點離開觸發。
  • 但使用者點擊建議項目(<li>)時,焦點先離開輸入框觸發 onblur,導致下拉框隱藏,隨後 onclick 才執行 fillin(),造成「點擊無效、需點兩次」或「閃爍」體驗。

核心解決方案:mousedown + 延遲隱藏

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>AJAX 搜尋建議 - 自動關閉修正版</title>
<style>
#livesearch {
    position: absolute;
    width: 300px;
    border: 1px solid #999;
    background: #fff;
    display: none;
    max-height: 200px;
    overflow-y: auto;
    z-index: 1000;
}
#livesearch ul { margin: 0; padding: 0; list-style: none; }
#livesearch li { padding: 8px 12px; cursor: pointer; }
#livesearch li:hover { background: #f0f0f0; }
</style>
</head>
<body>

<h3>搜尋建議示範</h3>
<div style="position: relative; width: 300px;">
    <input type="text" id="txt1" size="30" autocomplete="off" placeholder="輸入關鍵字...">
    <div id="livesearch"></div>
</div>

<script>
const input = document.getElementById('txt1');
const suggestBox = document.getElementById('livesearch');
let hideTimer = null;
let isMouseDownOnSuggest = false;

// 1. 輸入框事件
input.addEventListener('input', debounce(doSearch, 200));
input.addEventListener('focus', () => {
    if (suggestBox.dataset.hasContent === 'true') suggestBox.style.display = 'block';
});

// 2. 建議框滑鼠事件:阻止輸入框 blur 隱藏
suggestBox.addEventListener('mousedown', (e) => {
    isMouseDownOnSuggest = true;
    e.preventDefault(); // 關鍵:阻止輸入框失去焦點
});

suggestBox.addEventListener('click', (e) => {
    const li = e.target.closest('li');
    if (li) {
        input.value = li.textContent;
        suggestBox.style.display = 'none';
        suggestBox.dataset.hasContent = 'false';
    }
    isMouseDownOnSuggest = false;
});

// 3. 輸入框 blur:延遲隱藏,給 suggestBox click 時間執行
input.addEventListener('blur', () => {
    hideTimer = setTimeout(() => {
        if (!isMouseDownOnSuggest) {
            suggestBox.style.display = 'none';
        }
    }, 200);
});

// 4. 點擊文檔其他區域關閉
document.addEventListener('click', (e) => {
    if (!input.contains(e.target) && !suggestBox.contains(e.target)) {
        suggestBox.style.display = 'none';
    }
});

// 5. 防抖搜尋
function debounce(fn, delay) {
    let timer = null;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => fn(...args), delay);
    };
}

function doSearch() {
    const kw = input.value.trim();
    if (!kw) {
        suggestBox.innerHTML = '';
        suggestBox.style.display = 'none';
        suggestBox.dataset.hasContent = 'false';
        return;
    }
    // 模擬 AJAX(實際替換為 fetch)
    setTimeout(() => {
        const mockData = ['蘋果', '蘋果手機', '蘋果筆電', '香蕉', '香蕉牛奶'].filter(s => s.includes(kw));
        if (mockData.length) {
            suggestBox.innerHTML = '
    ' + mockData.map(s => `
  • ${s}
  • `).join('') + '
'; suggestBox.style.display = 'block'; suggestBox.dataset.hasContent = 'true'; } else { suggestBox.style.display = 'none'; suggestBox.dataset.hasContent = 'false'; } }, 100); } </script> </body> </html>

關鍵技術點解析

技術點作用
mousedown + preventDefault()阻止瀏覽器預設行為:滑鼠按下建議項時,輸入框不會失去焦點,blur 不會立即觸發
blur + setTimeout(200ms)延遲隱藏,給 click 事件足夠時間執行 fillin()
isMouseDownOnSuggest 旗標區分「點擊建議項」(不隱藏)與「點擊其他區域」(隱藏)
document.click 委派點擊頁面任意非輸入框/建議框區域時強制關閉
debounce輸入時延遲 200ms 發送請求,避免頻繁查詢
position: absolute + z-index建議框脫離文檔流,覆蓋在其他內容上方

現代化改良建議

  1. 使用 fetch + AbortController:取代舊式 XMLHttpRequest,支援請求取消。
  2. 鍵盤導航支援:keydown 處理 ArrowUp/Down、Enter、Escape,完整鍵盤可及性。
  3. ARIA 屬性:role="listbox", aria-expanded, aria-activedescendant,螢幕閱讀器支援。
  4. 組件化封裝:Vue/React/Alpine.js 組件,狀態管理更清晰。

總結

「點擊外部自動關閉」的核心在於**事件順序控制**:用 mousedown preventDefault 阻止焦點轉移,配合 blur 延遲 給予點擊處理時間窗,再以 document.click 委派 覆蓋所有其他點擊場景。此模式適用於所有「下拉選單、自動完成、彈出選單」類 UI 組件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved