// 全局MeNav对象 - 用于浏览器扩展 window.MeNav = { version: "1.0.0", // 获取配置数据 getConfig: function() { const configData = document.getElementById('menav-config-data'); return configData ? JSON.parse(configData.textContent) : null; }, // 获取元素的唯一标识符 _getElementId: function(element) { const type = element.getAttribute('data-type'); if (type === 'nav-item') { return element.getAttribute('data-id'); } else if (type === 'social-link') { return element.getAttribute('data-url'); } else { return element.getAttribute('data-name'); } }, // 根据类型和ID查找元素 _findElement: function(type, id) { let selector; if (type === 'nav-item') { selector = `[data-type="${type}"][data-id="${id}"]`; } else if (type === 'social-link') { selector = `[data-type="${type}"][data-url="${id}"]`; } else { selector = `[data-type="${type}"][data-name="${id}"]`; } return document.querySelector(selector); }, // 更新DOM元素 updateElement: function(type, id, newData) { const element = this._findElement(type, id); if (!element) return false; if (type === 'site') { // 更新站点卡片 if (newData.url) { element.href = newData.url; element.setAttribute('data-url', newData.url); } if (newData.name) { element.querySelector('h3').textContent = newData.name; element.setAttribute('data-name', newData.name); } if (newData.description) { element.querySelector('p').textContent = newData.description; element.setAttribute('data-description', newData.description); } if (newData.icon) { // 优先更新站点卡片中的回退图标(favicon模式下存在) const iconElement = element.querySelector('i.icon-fallback') || element.querySelector('i'); if (iconElement) { iconElement.className = newData.icon; } element.setAttribute('data-icon', newData.icon); } if (newData.title) element.title = newData.title; // 触发元素更新事件 this.events.emit('elementUpdated', { id: id, type: 'site', data: newData }); return true; } else if (type === 'category') { // 更新分类 if (newData.name) { const titleElement = element.querySelector('h2'); if (titleElement) { // 保留图标 const iconElement = titleElement.querySelector('i'); const iconClass = iconElement ? iconElement.className : ''; titleElement.innerHTML = ` ${newData.name}`; } element.setAttribute('data-name', newData.name); } if (newData.icon) { element.setAttribute('data-icon', newData.icon); } // 触发元素更新事件 this.events.emit('elementUpdated', { id: id, type: 'category', data: newData }); return true; } else if (type === 'nav-item') { // 更新导航项 if (newData.name) { const textElement = element.querySelector('.nav-text'); if (textElement) { textElement.textContent = newData.name; } element.setAttribute('data-name', newData.name); } if (newData.icon) { const iconElement = element.querySelector('i'); if (iconElement) { iconElement.className = newData.icon; } element.setAttribute('data-icon', newData.icon); } // 触发元素更新事件 this.events.emit('elementUpdated', { id: id, type: 'nav-item', data: newData }); return true; } else if (type === 'social-link') { // 更新社交链接 if (newData.url) { element.href = newData.url; element.setAttribute('data-url', newData.url); } if (newData.name) { const textElement = element.querySelector('.nav-text'); if (textElement) { textElement.textContent = newData.name; } element.setAttribute('data-name', newData.name); } if (newData.icon) { const iconElement = element.querySelector('i'); if (iconElement) { iconElement.className = newData.icon; } element.setAttribute('data-icon', newData.icon); } // 触发元素更新事件 this.events.emit('elementUpdated', { id: id, type: 'social-link', data: newData }); return true; } return false; }, // 添加新元素 addElement: function(type, parentId, data) { let parent; if (type === 'site') { // 查找父级分类 parent = document.querySelector(`[data-type="category"][data-name="${parentId}"]`); if (!parent) return null; // 添加站点卡片到分类 const sitesGrid = parent.querySelector('[data-container="sites"]'); if (!sitesGrid) return null; // 创建新的站点卡片 const newSite = document.createElement('a'); newSite.className = 'site-card'; newSite.href = data.url || '#'; newSite.title = data.name + (data.description ? ' - ' + data.description : ''); // 设置数据属性 newSite.setAttribute('data-type', 'site'); newSite.setAttribute('data-name', data.name || '未命名站点'); newSite.setAttribute('data-url', data.url || ''); newSite.setAttribute('data-icon', data.icon || 'fas fa-link'); newSite.setAttribute('data-description', data.description || ''); // 添加内容(根据图标模式渲染) try { const cfg = window.MeNav && typeof window.MeNav.getConfig === 'function' ? window.MeNav.getConfig() : null; const iconsMode = (cfg && (cfg.data?.icons?.mode || cfg.icons?.mode)) || 'favicon'; if (iconsMode === 'favicon' && data.url && /^https?:\/\//i.test(data.url)) { const faviconUrl = `https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${encodeURIComponent(data.url)}&size=32`; newSite.innerHTML = ` ${(data.name || '站点')} favicon

${data.name || '未命名站点'}

${data.description || ''}

`; } else { newSite.innerHTML = `

${data.name || '未命名站点'}

${data.description || ''}

`; } } catch (e) { newSite.innerHTML = `

${data.name || '未命名站点'}

${data.description || ''}

`; } // 添加到DOM sitesGrid.appendChild(newSite); // 移除"暂无网站"提示(如果存在) const emptyMessage = sitesGrid.querySelector('.empty-sites'); if (emptyMessage) { emptyMessage.remove(); } // 触发元素添加事件 this.events.emit('elementAdded', { id: data.name, type: 'site', parentId: parentId, data: data }); return data.name; } else if (type === 'category') { // 查找父级页面容器 parent = document.querySelector(`[data-container="categories"]`); if (!parent) return null; // 创建新的分类 const newCategory = document.createElement('section'); newCategory.className = 'category'; // 设置数据属性 newCategory.setAttribute('data-type', 'category'); newCategory.setAttribute('data-name', data.name || '未命名分类'); newCategory.setAttribute('data-icon', data.icon || 'fas fa-folder'); newCategory.setAttribute('data-container', 'categories'); // 添加内容 newCategory.innerHTML = `

${data.name || '未命名分类'}

暂无网站

`; // 添加到DOM parent.appendChild(newCategory); // 触发元素添加事件 this.events.emit('elementAdded', { id: data.name, type: 'category', data: data }); return data.name; } return null; }, // 删除元素 removeElement: function(type, id) { const element = this._findElement(type, id); if (!element) return false; // 获取父级容器(如果是站点卡片) let parentId = null; if (type === 'site') { const categoryElement = element.closest('[data-type="category"]'); if (categoryElement) { parentId = categoryElement.getAttribute('data-name'); } } // 删除元素 element.remove(); // 触发元素删除事件 this.events.emit('elementRemoved', { id: id, type: type, parentId: parentId }); return true; }, // 获取所有元素 getAllElements: function(type) { return Array.from(document.querySelectorAll(`[data-type="${type}"]`)).map(el => { const id = this._getElementId(el); return { id: id, type: type, element: el }; }); }, // 事件系统 events: { listeners: {}, // 添加事件监听器 on: function(event, callback) { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event].push(callback); return this; }, // 触发事件 emit: function(event, data) { if (this.listeners[event]) { this.listeners[event].forEach(callback => callback(data)); } return this; }, // 移除事件监听器 off: function(event, callback) { if (this.listeners[event]) { if (callback) { this.listeners[event] = this.listeners[event].filter(cb => cb !== callback); } else { delete this.listeners[event]; } } return this; } } }; document.addEventListener('DOMContentLoaded', () => { // 先声明所有状态变量 let isSearchActive = false; let currentPageId = 'home'; let isInitialLoad = true; let isSidebarOpen = false; let isSearchOpen = false; let isLightTheme = false; // 主题状态 let isSidebarCollapsed = false; // 侧边栏折叠状态 let pages; // 页面元素的全局引用 let currentSearchEngine = 'local'; // 当前选择的搜索引擎 // 搜索索引,用于提高搜索效率 let searchIndex = { initialized: false, items: [] }; // 搜索引擎配置 const searchEngines = { local: { name: '本地搜索', icon: 'fas fa-search', url: null // 本地搜索不需要URL }, google: { name: 'Google搜索', icon: 'fab fa-google', url: 'https://www.google.com/search?q=' }, bing: { name: 'Bing搜索', icon: 'fab fa-microsoft', url: 'https://www.bing.com/search?q=' }, baidu: { name: '百度搜索', icon: 'fas fa-paw', url: 'https://www.baidu.com/s?wd=' } }; // 获取DOM元素 - 基本元素 const searchInput = document.getElementById('search'); const searchBox = document.querySelector('.search-box'); const searchResultsPage = document.getElementById('search-results'); const searchSections = searchResultsPage.querySelectorAll('.search-section'); // 搜索引擎相关元素 const searchIcon = document.querySelector('.search-icon'); const searchEngineToggle = document.querySelector('.search-engine-toggle'); const searchEngineDropdown = document.querySelector('.search-engine-dropdown'); const searchEngineOptions = document.querySelectorAll('.search-engine-option'); // 移动端元素 const menuToggle = document.querySelector('.menu-toggle'); const searchToggle = document.querySelector('.search-toggle'); const sidebar = document.querySelector('.sidebar'); const searchContainer = document.querySelector('.search-container'); const overlay = document.querySelector('.overlay'); // 侧边栏折叠功能 const sidebarToggle = document.querySelector('.sidebar-toggle'); const content = document.querySelector('.content'); // 主题切换元素 const themeToggle = document.querySelector('.theme-toggle'); const themeIcon = themeToggle.querySelector('i'); // 滚动进度条元素 const scrollProgress = document.querySelector('.scroll-progress'); // 移除预加载类,允许CSS过渡效果 document.documentElement.classList.remove('preload'); // 应用从localStorage读取的主题设置 if (document.documentElement.classList.contains('theme-preload')) { document.documentElement.classList.remove('theme-preload'); document.body.classList.add('light-theme'); isLightTheme = true; } // 应用从localStorage读取的侧边栏状态 if (document.documentElement.classList.contains('sidebar-collapsed-preload')) { document.documentElement.classList.remove('sidebar-collapsed-preload'); sidebar.classList.add('collapsed'); content.classList.add('expanded'); isSidebarCollapsed = true; } // 即时移除loading类,确保侧边栏可见 document.body.classList.remove('loading'); document.body.classList.add('loaded'); // 侧边栏折叠功能 function toggleSidebarCollapse() { // 仅在交互时启用布局相关动画,避免首屏闪烁 document.documentElement.classList.add('with-anim'); isSidebarCollapsed = !isSidebarCollapsed; // 使用 requestAnimationFrame 确保平滑过渡 requestAnimationFrame(() => { sidebar.classList.toggle('collapsed', isSidebarCollapsed); content.classList.toggle('expanded', isSidebarCollapsed); // 保存折叠状态到localStorage localStorage.setItem('sidebarCollapsed', isSidebarCollapsed ? 'true' : 'false'); }); } // 初始化侧边栏折叠状态 - 已在页面加载前处理,此处仅完成图标状态初始化等次要任务 function initSidebarState() { // 从localStorage获取侧边栏状态 const savedState = localStorage.getItem('sidebarCollapsed'); // 图标状态与折叠状态保持一致 if (savedState === 'true' && !isMobile()) { isSidebarCollapsed = true; } else { isSidebarCollapsed = false; } } // 侧边栏折叠按钮点击事件 if (sidebarToggle) { sidebarToggle.addEventListener('click', toggleSidebarCollapse); } // 主题切换功能 function toggleTheme() { isLightTheme = !isLightTheme; document.body.classList.toggle('light-theme', isLightTheme); // 更新图标 if (isLightTheme) { themeIcon.classList.remove('fa-moon'); themeIcon.classList.add('fa-sun'); } else { themeIcon.classList.remove('fa-sun'); themeIcon.classList.add('fa-moon'); } // 保存主题偏好到localStorage localStorage.setItem('theme', isLightTheme ? 'light' : 'dark'); } // 初始化主题 - 已在页面加载前处理,此处仅完成图标状态初始化等次要任务 function initTheme() { // 从localStorage获取主题偏好 const savedTheme = localStorage.getItem('theme'); // 更新图标状态以匹配当前主题 if (savedTheme === 'light') { isLightTheme = true; themeIcon.classList.remove('fa-moon'); themeIcon.classList.add('fa-sun'); } else { isLightTheme = false; themeIcon.classList.remove('fa-sun'); themeIcon.classList.add('fa-moon'); } } // 主题切换按钮点击事件 themeToggle.addEventListener('click', toggleTheme); // 初始化搜索索引 function initSearchIndex() { if (searchIndex.initialized) return; searchIndex.items = []; try { // 为每个页面创建索引 if (!pages) { pages = document.querySelectorAll('.page'); } pages.forEach(page => { if (page.id === 'search-results') return; const pageId = page.id; page.querySelectorAll('.site-card').forEach(card => { try { const title = card.querySelector('h3')?.textContent?.toLowerCase() || ''; const description = card.querySelector('p')?.textContent?.toLowerCase() || ''; const url = card.href || card.getAttribute('href') || '#'; const icon = card.querySelector('i.icon-fallback')?.className || card.querySelector('i')?.className || ''; // 将卡片信息添加到索引中 searchIndex.items.push({ pageId, title, description, url, icon, element: card, // 预先计算搜索文本,提高搜索效率 searchText: (title + ' ' + description).toLowerCase() }); } catch (cardError) { console.error('Error processing card:', cardError); } }); }); searchIndex.initialized = true; } catch (error) { console.error('Error initializing search index:', error); searchIndex.initialized = true; // 防止反复尝试初始化 } } // 移动端菜单切换 function toggleSidebar() { isSidebarOpen = !isSidebarOpen; sidebar.classList.toggle('active', isSidebarOpen); overlay.classList.toggle('active', isSidebarOpen); if (isSearchOpen) { toggleSearch(); } } // 移动端搜索切换 function toggleSearch() { isSearchOpen = !isSearchOpen; searchContainer.classList.toggle('active', isSearchOpen); overlay.classList.toggle('active', isSearchOpen); if (isSearchOpen) { searchInput.focus(); if (isSidebarOpen) { toggleSidebar(); } } } // 关闭所有移动端面板 function closeAllPanels() { if (isSidebarOpen) { toggleSidebar(); } if (isSearchOpen) { toggleSearch(); } } // 移动端事件监听 menuToggle.addEventListener('click', toggleSidebar); searchToggle.addEventListener('click', toggleSearch); overlay.addEventListener('click', closeAllPanels); // 检查是否是移动设备 function isMobile() { return window.innerWidth <= 768; } // 窗口大小改变时处理 window.addEventListener('resize', () => { if (!isMobile()) { sidebar.classList.remove('active'); searchContainer.classList.remove('active'); overlay.classList.remove('active'); isSidebarOpen = false; isSearchOpen = false; } else { // 在移动设备下,重置侧边栏折叠状态 sidebar.classList.remove('collapsed'); content.classList.remove('expanded'); } // 重新计算滚动进度 updateScrollProgress(); }); // 更新滚动进度条 function updateScrollProgress() { const scrollTop = content.scrollTop || 0; const scrollHeight = content.scrollHeight - content.clientHeight || 1; const scrollPercent = (scrollTop / scrollHeight) * 100; scrollProgress.style.width = scrollPercent + '%'; } // 监听内容区域的滚动事件 content.addEventListener('scroll', updateScrollProgress); // 初始化时更新一次滚动进度 updateScrollProgress(); // 页面切换功能 function showPage(pageId, skipSearchReset = false) { if (currentPageId === pageId && !skipSearchReset && !isInitialLoad) return; currentPageId = pageId; // 使用 RAF 确保动画流畅 requestAnimationFrame(() => { if (!pages) { pages = document.querySelectorAll('.page'); } pages.forEach(page => { const shouldBeActive = page.id === pageId; if (shouldBeActive !== page.classList.contains('active')) { page.classList.toggle('active', shouldBeActive); } }); // 初始加载完成后设置标志 if (isInitialLoad) { isInitialLoad = false; document.body.classList.add('loaded'); } }); // 重置滚动位置并更新进度条 content.scrollTop = 0; updateScrollProgress(); // 只有在非搜索状态下才重置搜索 if (!skipSearchReset) { searchInput.value = ''; resetSearch(); } } // 搜索功能 function performSearch(searchTerm) { // 确保搜索索引已初始化 if (!searchIndex.initialized) { initSearchIndex(); } searchTerm = searchTerm.toLowerCase().trim(); // 如果搜索框为空,重置所有内容 if (!searchTerm) { resetSearch(); return; } if (!isSearchActive) { isSearchActive = true; } try { // 使用搜索索引进行搜索 const searchResults = new Map(); let hasResults = false; // 使用更高效的搜索算法 const matchedItems = searchIndex.items.filter(item => { return item.searchText.includes(searchTerm) || PinyinMatch.match(item.searchText, searchTerm);; }); // 按页面分组结果 matchedItems.forEach(item => { if (!searchResults.has(item.pageId)) { searchResults.set(item.pageId, []); } // 克隆元素以避免修改原始DOM searchResults.get(item.pageId).push(item.element.cloneNode(true)); hasResults = true; }); // 使用requestAnimationFrame批量更新DOM,减少重排重绘 requestAnimationFrame(() => { try { // 清空并隐藏所有搜索区域 searchSections.forEach(section => { try { const grid = section.querySelector('.sites-grid'); if (grid) { grid.innerHTML = ''; // 使用innerHTML清空,比removeChild更高效 } section.style.display = 'none'; } catch (sectionError) { console.error('Error clearing search section'); } }); // 使用DocumentFragment批量添加DOM元素,减少重排 searchResults.forEach((matches, pageId) => { const section = searchResultsPage.querySelector(`[data-section="${pageId}"]`); if (section) { try { const grid = section.querySelector('.sites-grid'); if (grid) { const fragment = document.createDocumentFragment(); matches.forEach(card => { // 高亮匹配文本 highlightSearchTerm(card, searchTerm); fragment.appendChild(card); }); grid.appendChild(fragment); section.style.display = 'block'; } } catch (gridError) { console.error('Error updating search results grid'); } } }); // 更新搜索结果页面状态 const subtitle = searchResultsPage.querySelector('.subtitle'); if (subtitle) { subtitle.textContent = hasResults ? `在所有页面中找到 ${matchedItems.length} 个匹配项` : '未找到匹配的结果'; } // 显示搜索结果页面 if (currentPageId !== 'search-results') { currentPageId = 'search-results'; pages.forEach(page => { page.classList.toggle('active', page.id === 'search-results'); }); } // 更新搜索状态样式 searchBox.classList.toggle('has-results', hasResults); searchBox.classList.toggle('no-results', !hasResults); } catch (uiError) { console.error('Error updating search UI'); } }); } catch (searchError) { console.error('Error performing search'); } } // 高亮搜索匹配文本 function highlightSearchTerm(card, searchTerm) { if (!card || !searchTerm) return; try { const title = card.querySelector('h3'); const description = card.querySelector('p'); if (!title || !description) return; // 安全地高亮标题中的匹配文本 if (title.textContent.toLowerCase().includes(searchTerm)) { const titleText = title.textContent; const regex = new RegExp(`(${escapeRegExp(searchTerm)})`, 'gi'); // 创建安全的DOM结构而不是直接使用innerHTML const titleFragment = document.createDocumentFragment(); let lastIndex = 0; let match; // 使用正则表达式查找所有匹配项 const titleRegex = new RegExp(regex); while ((match = titleRegex.exec(titleText)) !== null) { // 添加匹配前的文本 if (match.index > lastIndex) { titleFragment.appendChild(document.createTextNode( titleText.substring(lastIndex, match.index) )); } // 添加高亮的匹配文本 const span = document.createElement('span'); span.className = 'highlight'; span.textContent = match[0]; titleFragment.appendChild(span); lastIndex = match.index + match[0].length; // 防止无限循环 if (titleRegex.lastIndex === 0) break; } // 添加剩余文本 if (lastIndex < titleText.length) { titleFragment.appendChild(document.createTextNode( titleText.substring(lastIndex) )); } // 清空原标题并添加新内容 while (title.firstChild) { title.removeChild(title.firstChild); } title.appendChild(titleFragment); } else if (PinyinMatch.match(title.textContent, searchTerm)) { const arr = PinyinMatch.match(title.textContent, searchTerm); const [start, end] = arr; title.innerHTML = title.textContent.slice(0, start) + `${title.textContent.slice(start, end + 1)}` + title.textContent.slice(end + 1); } // 安全地高亮描述中的匹配文本 if (description.textContent.toLowerCase().includes(searchTerm)) { const descText = description.textContent; const regex = new RegExp(`(${escapeRegExp(searchTerm)})`, 'gi'); // 创建安全的DOM结构而不是直接使用innerHTML const descFragment = document.createDocumentFragment(); let lastIndex = 0; let match; // 使用正则表达式查找所有匹配项 const descRegex = new RegExp(regex); while ((match = descRegex.exec(descText)) !== null) { // 添加匹配前的文本 if (match.index > lastIndex) { descFragment.appendChild(document.createTextNode( descText.substring(lastIndex, match.index) )); } // 添加高亮的匹配文本 const span = document.createElement('span'); span.className = 'highlight'; span.textContent = match[0]; descFragment.appendChild(span); lastIndex = match.index + match[0].length; // 防止无限循环 if (descRegex.lastIndex === 0) break; } // 添加剩余文本 if (lastIndex < descText.length) { descFragment.appendChild(document.createTextNode( descText.substring(lastIndex) )); } // 清空原描述并添加新内容 while (description.firstChild) { description.removeChild(description.firstChild); } description.appendChild(descFragment); } else if (PinyinMatch.match(description.textContent, searchTerm)) { const arr = PinyinMatch.match(description.textContent, searchTerm); const [start, end] = arr; description.innerHTML = description.textContent.slice(0, start) + `${description.textContent.slice(start, end + 1)}` + description.textContent.slice(end + 1); } } catch (error) { console.error('Error highlighting search term'); } } // 转义正则表达式特殊字符 function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } // 重置搜索状态 function resetSearch() { if (!isSearchActive) return; isSearchActive = false; try { requestAnimationFrame(() => { try { // 清空搜索结果 searchSections.forEach(section => { try { const grid = section.querySelector('.sites-grid'); if (grid) { while (grid.firstChild) { grid.removeChild(grid.firstChild); } } section.style.display = 'none'; } catch (sectionError) { console.error('Error clearing search section'); } }); // 移除搜索状态样式 searchBox.classList.remove('has-results', 'no-results'); // 恢复到当前激活的页面 const currentActiveNav = document.querySelector('.nav-item.active'); if (currentActiveNav) { const targetPageId = currentActiveNav.getAttribute('data-page'); if (targetPageId && currentPageId !== targetPageId) { currentPageId = targetPageId; pages.forEach(page => { page.classList.toggle('active', page.id === targetPageId); }); } } else { // 如果没有激活的导航项,默认显示首页 currentPageId = 'home'; pages.forEach(page => { page.classList.toggle('active', page.id === 'home'); }); } } catch (resetError) { console.error('Error resetting search UI'); } }); } catch (error) { console.error('Error in resetSearch'); } } // 搜索输入事件(使用防抖) const debounce = (fn, delay) => { let timer = null; return (...args) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); timer = null; }, delay); }; }; const debouncedSearch = debounce(performSearch, 300); searchInput.addEventListener('input', (e) => { // 只有在选择了本地搜索时,才在输入时实时显示本地搜索结果 if (currentSearchEngine === 'local') { debouncedSearch(e.target.value); } else { // 对于非本地搜索,重置之前的本地搜索结果(如果有) if (isSearchActive) { resetSearch(); } } }); // 初始化搜索引擎设置 function initSearchEngine() { // 从本地存储获取上次选择的搜索引擎 const savedEngine = localStorage.getItem('searchEngine'); if (savedEngine && searchEngines[savedEngine]) { currentSearchEngine = savedEngine; } // 设置当前搜索引擎的激活状态及图标 updateSearchEngineUI(); // 初始化搜索引擎下拉菜单事件 const toggleEngineDropdown = () => { const next = !searchEngineDropdown.classList.contains('active'); searchEngineDropdown.classList.toggle('active', next); if (searchBox) { searchBox.classList.toggle('dropdown-open', next); } if (searchEngineToggle) { searchEngineToggle.setAttribute('aria-expanded', String(next)); } }; if (searchIcon) { searchIcon.addEventListener('click', (e) => { e.stopPropagation(); toggleEngineDropdown(); }); } if (searchEngineToggle) { searchEngineToggle.addEventListener('click', (e) => { e.stopPropagation(); toggleEngineDropdown(); }); // 键盘可访问性:Enter/Space 触发 searchEngineToggle.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); toggleEngineDropdown(); } }); } // 点击搜索引擎选项 searchEngineOptions.forEach(option => { // 初始化激活状态 if (option.getAttribute('data-engine') === currentSearchEngine) { option.classList.add('active'); } option.addEventListener('click', (e) => { e.stopPropagation(); // 获取选中的搜索引擎 const engine = option.getAttribute('data-engine'); // 更新当前搜索引擎 if (engine && searchEngines[engine]) { // 如果搜索引擎变更,且之前有活跃的本地搜索结果,重置搜索状态 if (currentSearchEngine !== engine && isSearchActive) { resetSearch(); } currentSearchEngine = engine; localStorage.setItem('searchEngine', engine); // 更新UI显示 updateSearchEngineUI(); // 关闭下拉菜单 searchEngineDropdown.classList.remove('active'); if (searchBox) { searchBox.classList.remove('dropdown-open'); } } }); }); // 点击页面其他位置关闭下拉菜单 document.addEventListener('click', () => { searchEngineDropdown.classList.remove('active'); if (searchBox) { searchBox.classList.remove('dropdown-open'); } }); } // 更新搜索引擎UI显示 function updateSearchEngineUI() { // 移除所有选项的激活状态 searchEngineOptions.forEach(option => { option.classList.remove('active'); // 如果是当前选中的搜索引擎,添加激活状态 if (option.getAttribute('data-engine') === currentSearchEngine) { option.classList.add('active'); } }); // 更新搜索图标以反映当前搜索引擎 if (searchIcon) { // 清除所有类,保留基本的search-icon类 const classList = searchIcon.className.split(' ').filter(cls => cls === 'search-icon'); searchIcon.className = classList.join(' '); // 添加当前搜索引擎的图标类 const engine = searchEngines[currentSearchEngine]; if (engine) { const iconClasses = engine.icon.split(' '); iconClasses.forEach(cls => { searchIcon.classList.add(cls); }); // 更新标题提示 searchIcon.setAttribute('title', engine.name); } } } // 执行搜索(根据选择的搜索引擎) function executeSearch(searchTerm) { if (!searchTerm.trim()) return; // 根据当前搜索引擎执行搜索 if (currentSearchEngine === 'local') { // 执行本地搜索 performSearch(searchTerm); } else { // 使用外部搜索引擎 const engine = searchEngines[currentSearchEngine]; if (engine && engine.url) { // 打开新窗口进行搜索 window.open(engine.url + encodeURIComponent(searchTerm), '_blank'); } } } // 搜索框事件处理 searchInput.addEventListener('keyup', (e) => { if (e.key === 'Escape') { searchInput.value = ''; resetSearch(); } else if (e.key === 'Enter') { executeSearch(searchInput.value); // 在移动设备上,执行搜索后自动关闭搜索面板 if (isMobile() && isSearchOpen) { closeAllPanels(); } } }); // 阻止搜索框的回车默认行为 searchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); } }); // 初始化 window.addEventListener('load', () => { // 获取可能在HTML生成后才存在的DOM元素 const siteCards = document.querySelectorAll('.site-card'); const categories = document.querySelectorAll('.category'); const navItems = document.querySelectorAll('.nav-item'); const navItemWrappers = document.querySelectorAll('.nav-item-wrapper'); const submenuItems = document.querySelectorAll('.submenu-item'); pages = document.querySelectorAll('.page'); // 初始化主题 initTheme(); // 初始化侧边栏状态 initSidebarState(); // 初始化搜索引擎选择 initSearchEngine(); // 初始化MeNav对象版本信息 try { const config = window.MeNav.getConfig(); if (config && config.version) { window.MeNav.version = config.version; console.log('MeNav API initialized with version:', config.version); } } catch (error) { console.error('Error initializing MeNav API:', error); } // 立即执行初始化,不再使用requestAnimationFrame延迟 // 显示首页 showPage('home'); // 添加载入动画 categories.forEach((category, index) => { setTimeout(() => { category.style.opacity = '1'; }, index * 100); }); // 初始展开当前页面的子菜单 const activeNavItem = document.querySelector('.nav-item.active'); if (activeNavItem) { const activeWrapper = activeNavItem.closest('.nav-item-wrapper'); if (activeWrapper) { } } // 导航项点击效果 navItems.forEach(item => { item.addEventListener('click', (e) => { if (item.getAttribute('target') === '_blank') return; e.preventDefault(); // 获取当前项的父级wrapper const wrapper = item.closest('.nav-item-wrapper'); const hasSubmenu = wrapper && wrapper.querySelector('.submenu'); // 处理子菜单展开/折叠 if (hasSubmenu) { // 如果点击的导航项已经激活且有子菜单,则切换子菜单展开状态 if (item.classList.contains('active')) { wrapper.classList.toggle('expanded'); } else { // 关闭所有已展开的子菜单 navItemWrappers.forEach(navWrapper => { if (navWrapper !== wrapper) { navWrapper.classList.remove('expanded'); } }); // 展开当前子菜单 wrapper.classList.add('expanded'); } } // 激活导航项 navItems.forEach(nav => { nav.classList.toggle('active', nav === item); }); const pageId = item.getAttribute('data-page'); if (pageId) { showPage(pageId); // 在移动端视图下点击导航项后自动收起侧边栏 if (isMobile() && isSidebarOpen && !hasSubmenu) { closeAllPanels(); } } }); }); // 子菜单项点击效果 submenuItems.forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); // 获取页面ID和分类名称 const pageId = item.getAttribute('data-page'); const categoryName = item.getAttribute('data-category'); if (pageId) { // 清除所有子菜单项的激活状态 submenuItems.forEach(subItem => { subItem.classList.remove('active'); }); // 激活当前子菜单项 item.classList.add('active'); // 激活相应的导航项 navItems.forEach(nav => { nav.classList.toggle('active', nav.getAttribute('data-page') === pageId); }); // 显示对应页面 showPage(pageId); // 等待页面切换完成后滚动到对应分类 setTimeout(() => { // 查找目标分类元素 const targetPage = document.getElementById(pageId); if (targetPage) { const targetCategory = Array.from(targetPage.querySelectorAll('.category h2')).find( heading => heading.textContent.trim().includes(categoryName) ); if (targetCategory) { // 优化的滚动实现:滚动到使目标分类位于视口1/4处(更靠近顶部位置) try { // 直接获取所需元素和属性,减少重复查询 const contentElement = document.querySelector('.content'); if (contentElement && contentElement.scrollHeight > contentElement.clientHeight) { // 获取目标元素相对于内容区域的位置 const rect = targetCategory.getBoundingClientRect(); const containerRect = contentElement.getBoundingClientRect(); // 计算目标应该在视口中的位置(视口高度的1/4处) const desiredPosition = containerRect.height / 4; // 计算需要滚动的位置 const scrollPosition = contentElement.scrollTop + rect.top - containerRect.top - desiredPosition; // 执行滚动 contentElement.scrollTo({ top: scrollPosition, behavior: 'smooth' }); } else { // 回退到基本滚动方式 targetCategory.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } catch (error) { console.error('Error during scroll:', error); // 回退到基本滚动方式 targetCategory.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } } }, 25); // 延迟时间 // 在移动端视图下点击子菜单项后自动收起侧边栏 if (isMobile() && isSidebarOpen) { closeAllPanels(); } } }); }); // 初始化搜索索引(使用requestIdleCallback或setTimeout延迟初始化,避免影响页面加载) if ('requestIdleCallback' in window) { requestIdleCallback(() => initSearchIndex()); } else { setTimeout(initSearchIndex, 1000); } }); });