(() => { // 菜单搜索功能 class MenuSearch { constructor() { this.searchInput = document.querySelector('.sidebar-search-input'); this.searchIcon = document.querySelector('.search-icon'); this.menuItems = []; this.searchResults = []; this.isSearchVisible = false; this.init(); } init() { if (!this.searchInput) return; // 收集所有菜单项 this.collectMenuItems(); // 监听输入事件 this.searchInput.addEventListener('input', (e) => { this.handleSearch(e.target.value); }); // 监听焦点事件 this.searchInput.addEventListener('focus', () => { if (this.searchInput.value.trim()) { this.showSearchResults(); } }); // 监听失焦事件(延迟隐藏,以便点击搜索结果) this.searchInput.addEventListener('blur', () => { setTimeout(() => { this.hideSearchResults(); }, 200); }); // 监听键盘事件 this.searchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); this.navigateFirstResult(); } else if (e.key === 'Escape') { this.clearSearch(); this.searchInput.blur(); } }); // 创建搜索结果容器 this.createSearchResultsContainer(); } collectMenuItems() { // 收集主导航项 document.querySelectorAll('.topnav-item[data-route]').forEach(item => { const text = item.querySelector('.topnav-text')?.textContent.trim(); const route = item.dataset.route; const href = item.getAttribute('href'); if (text && route) { this.menuItems.push({ text, route, href, type: 'menu', element: item }); } }); // 收集下拉菜单项 document.querySelectorAll('.dropdown-item[data-route]').forEach(item => { const text = item.textContent.trim(); const route = item.dataset.route; const href = item.getAttribute('href'); const parentMenu = item.closest('.topnav-item.has-dropdown')?.querySelector('.topnav-text')?.textContent.trim(); if (text && route) { this.menuItems.push({ text, route, href, type: 'submenu', parent: parentMenu, element: item }); } }); } createSearchResultsContainer() { // 创建搜索结果下拉框 this.resultsContainer = document.createElement('div'); this.resultsContainer.className = 'search-results-container'; this.resultsContainer.innerHTML = `
`; // 插入到搜索框后面 const searchWrapper = this.searchInput.closest('.sidebar-search'); searchWrapper.appendChild(this.resultsContainer); // 添加样式 const style = document.createElement('style'); style.textContent = ` .sidebar-search { position: relative; } .search-results-container { position: absolute; top: 100%; left: 0; right: 0; background: var(--card-bg, #ffffff); border: 1px solid var(--border-color, #e0e0e0); border-radius: 0 0 8px 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); max-height: 300px; overflow-y: auto; z-index: 9999; display: none; } [data-theme="dark"] .search-results-container { background: var(--card-bg, #1a1a1a); border-color: var(--border-color, #333333); } .search-results-container.show { display: block; } .search-results-list { padding: 4px 0; } .search-result-item { padding: 8px 16px; cursor: pointer; transition: background-color 0.2s; display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text-color, #333333); background: transparent; } .search-result-item:hover { background: var(--hover-bg, #f5f5f5); } .search-result-item.active { background: var(--primary-color, #007bff); color: white !important; } .search-result-item .result-icon { opacity: 0.8; flex-shrink: 0; } .search-result-item .result-text { flex: 1; opacity: 1 !important; } .search-result-item .result-parent { font-size: 12px; opacity: 0.7; margin-left: 8px; } .search-result-item .result-highlight { font-weight: 600; color: var(--primary-color, #007bff); } .search-result-item.active .result-highlight { color: inherit !important; } .search-empty { padding: 16px; text-align: center; color: var(--text-muted, #666666); font-size: 14px; } .search-shortcut { padding: 8px 16px; border-top: 1px solid var(--border-color, #e0e0e0); font-size: 12px; color: var(--text-muted, #666666); } [data-theme="dark"] .search-result-item { color: var(--text-color, #e0e0e0); } [data-theme="dark"] .search-result-item:hover { background: var(--hover-bg, #2a2a2a); } [data-theme="dark"] .search-empty, [data-theme="dark"] .search-shortcut { color: var(--text-muted, #999999); } `; document.head.appendChild(style); } handleSearch(query) { const trimmedQuery = query.trim().toLowerCase(); if (!trimmedQuery) { this.hideSearchResults(); return; } // 搜索匹配的菜单项 this.searchResults = this.menuItems.filter(item => { return item.text.toLowerCase().includes(trimmedQuery) || (item.parent && item.parent.toLowerCase().includes(trimmedQuery)); }); // 按匹配度和类型排序 this.searchResults.sort((a, b) => { // 优先匹配开头的 const aStarts = a.text.toLowerCase().startsWith(trimmedQuery); const bStarts = b.text.toLowerCase().startsWith(trimmedQuery); if (aStarts && !bStarts) return -1; if (!aStarts && bStarts) return 1; // 主菜单优先于子菜单 if (a.type === 'menu' && b.type === 'submenu') return -1; if (a.type === 'submenu' && b.type === 'menu') return 1; // 按文本排序 return a.text.localeCompare(b.text); }); this.displaySearchResults(trimmedQuery); } displaySearchResults(query) { const resultsList = this.resultsContainer.querySelector('.search-results-list'); if (this.searchResults.length === 0) { resultsList.innerHTML = '
未找到匹配的菜单项
'; } else { resultsList.innerHTML = this.searchResults.map((item, index) => { const highlightedText = this.highlightText(item.text, query); const parentText = item.parent ? `${item.parent}` : ''; return `
${item.type === 'menu' ? '📄' : '📋'} ${highlightedText} ${parentText}
`; }).join(''); // 添加点击事件 resultsList.querySelectorAll('.search-result-item').forEach(item => { item.addEventListener('click', () => { const href = item.dataset.href; if (href) { window.location.href = href; } }); }); } // 添加快捷键提示 const shortcut = document.createElement('div'); shortcut.className = 'search-shortcut'; shortcut.innerHTML = '↑↓ 选择 Enter 确认 Esc 取消'; resultsList.appendChild(shortcut); this.showSearchResults(); } highlightText(text, query) { const regex = new RegExp(`(${query})`, 'gi'); return text.replace(regex, '$1'); } showSearchResults() { this.resultsContainer.classList.add('show'); this.isSearchVisible = true; } hideSearchResults() { this.resultsContainer.classList.remove('show'); this.isSearchVisible = false; } clearSearch() { this.searchInput.value = ''; this.hideSearchResults(); } navigateFirstResult() { if (this.searchResults.length > 0) { const firstResult = this.searchResults[0]; if (firstResult.href) { window.location.href = firstResult.href; } } } } // 初始化搜索功能 const menuSearch = new MenuSearch(); // 全局快捷键 Ctrl+K 或 Cmd+K 聚焦搜索框 document.addEventListener('keydown', (e) => { if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); menuSearch.searchInput?.focus(); } }); })();