您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在搜索结果页面添加智能搜索引擎切换功能,支持多种布局和自定义设置
当前为
// ==UserScript== // @name 全能搜索引擎切换助手 // @namespace http://tampermonkey.net/ // @version 1.6 // @description 在搜索结果页面添加智能搜索引擎切换功能,支持多种布局和自定义设置 // @author Yuze // @copyright 2025, Yuze (https://greasyfork.org/users/Yuze Guitar) // @license MIT // @match *://www.google.com/search* // @match *://www.google.co*/search* // @match *://www.bing.com/search* // @match *://cn.bing.com/search* // @match *://www.baidu.com/s* // @match *://www.sogou.com/web* // @match *://www.so.com/s* // @match *://duckduckgo.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 记录调试信息 const DEBUG = true; function log(...args) { if (DEBUG) { console.log('[搜索引擎切换助手]', ...args); } } // 错误处理 function handleError(error, context) { console.error(`[搜索引擎切换助手] 错误 (${context}):`, error); if (DEBUG) { console.trace(); } } // 检测操作系统 const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const modifierKey = isMac ? '⌘' : 'Alt+'; const modifierKeyCode = isMac ? 'metaKey' : 'altKey'; // 定义搜索引擎 const defaultEngines = [ { name: 'Google', icon: 'https://www.google.com/favicon.ico', url: 'https://www.google.com/search?q={query}', matchPattern: 'google\\.[^/]+/search', queryParam: 'q', shortcut: 'G' }, { name: 'Bing', icon: 'https://www.bing.com/favicon.ico', url: 'https://www.bing.com/search?q={query}', matchPattern: 'bing\\.com/search', queryParam: 'q', shortcut: 'B' }, { name: '百度', icon: 'https://www.baidu.com/favicon.ico', url: 'https://www.baidu.com/s?wd={query}', matchPattern: 'baidu\\.com/s', queryParam: 'wd', shortcut: 'D' }, { name: 'DuckDuckGo', // 内置图标数据,确保在任何环境下都能显示 icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI0RFNTgzMyIgZD0iTTEyIDFDNS45MiAxIDEgNS45MiAxIDEyczQuOTIgMTEgMTEgMTEgMTEtNC45MiAxMS0xMVMxOC4wOCAxIDEyIDF6bTMuNTggMTQuMWMwIC4wOS0uMDUuMi0uMTMuMjdsLS45My43Ni0uMDIuMDJhLjM4LjM4IDAgMCAxLS4yOC4xMmgtNS4xM2MtLjIyIDAtLjQtLjE4LS40LS40di0uOTctLjAxYzAtLjIyLjE4LS40LjQtLjRoNS4xNWEuMzguMzggMCAwIDEgLjI2LjEybC4wMS4wMi45My43NmEuMzQuMzQgMCAwIDEgLjEzLjI3eiIvPjwvc3ZnPg==', url: 'https://duckduckgo.com/?q={query}', matchPattern: 'duckduckgo\\.com', queryParam: 'q', shortcut: 'K' } ]; // 添加CSS样式 function addStyles() { try { GM_addStyle(` /* 主容器 */ #search-engine-switcher { position: fixed; top: 120px; left: 10px; z-index: 9999; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); padding: 10px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 14px; display: flex; flex-direction: column; gap: 12px; transition: all 0.3s ease; min-width: 120px; max-width: 180px; } /* 深色模式 */ @media (prefers-color-scheme: dark) { #search-engine-switcher { background: #333; color: #fff; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5); } #search-engine-switcher .engine-btn { color: #eee; } #search-engine-switcher .engine-btn:hover { background: #444; } #search-engine-switcher .collapse-btn { color: #ccc; } #search-engine-switcher.collapsed { background: rgba(51, 51, 51, 0.9); } } /* 折叠状态 - 优化折叠后的外观 */ #search-engine-switcher.collapsed { padding: 8px 10px; min-width: unset; max-width: unset; width: auto; } #search-engine-switcher.collapsed .engine-container { display: none; } #search-engine-switcher.collapsed .switcher-header { margin: 0; padding: 0; } #search-engine-switcher.collapsed .collapse-btn { transform: rotate(180deg); margin-left: 5px; } #search-engine-switcher.collapsed .switcher-title { margin: 0; font-size: 12px; white-space: nowrap; } /* 头部样式 */ .switcher-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; } .switcher-title { font-weight: bold; font-size: 14px; margin: 0; user-select: none; } .settings-btn, .collapse-btn { background: none; border: none; cursor: pointer; padding: 0; display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; opacity: 0.7; transition: opacity 0.2s; } .settings-btn:hover, .collapse-btn:hover { opacity: 1; } .header-actions { display: flex; gap: 8px; } /* 搜索引擎按钮容器 */ .engine-container { display: flex; flex-direction: column; gap: 8px; } /* 搜索引擎按钮 */ .engine-btn { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; border: none; background: none; cursor: pointer; color: #333; font-size: 14px; text-align: left; transition: background 0.2s; } .engine-btn:hover { background: #f0f0f0; } .engine-icon { width: 16px; height: 16px; object-fit: contain; } .shortcut { margin-left: auto; padding: 2px 4px; border-radius: 3px; background: #f0f0f0; color: #666; font-size: 10px; } @media (prefers-color-scheme: dark) { .shortcut { background: #444; color: #ccc; } } /* 设置面板样式 */ .settings-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10000; } .settings-container { background: #fff; border-radius: 8px; padding: 20px; width: 90%; max-width: 400px; max-height: 80vh; overflow-y: auto; } @media (prefers-color-scheme: dark) { .settings-container { background: #333; color: #fff; } } .settings-header { font-weight: bold; font-size: 18px; margin-bottom: 15px; } .settings-section { margin-bottom: 20px; } .section-title { font-weight: bold; margin-bottom: 10px; } .checkbox-group { display: flex; flex-direction: column; gap: 10px; } .settings-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; } .settings-button { padding: 8px 16px; border-radius: 4px; border: none; cursor: pointer; } .cancel-button { background: #f0f0f0; color: #333; } .save-button { background: #4285f4; color: white; } @media (prefers-color-scheme: dark) { .cancel-button { background: #555; color: #eee; } } /* Mac选项 */ .mac-options { display: flex; gap: 15px; margin-top: 10px; } .mac-option { display: flex; align-items: center; gap: 5px; } `); log('样式已添加'); } catch (error) { handleError(error, '添加样式'); } } // 获取启用的搜索引擎 function getEnabledEngines() { try { const settings = loadSettings(); const enabledEngineNames = settings.enabledEngines || defaultEngines.map(e => e.name); return defaultEngines.filter(engine => enabledEngineNames.includes(engine.name) ); } catch (error) { handleError(error, '获取启用的搜索引擎'); return defaultEngines; } } // 加载设置 function loadSettings() { try { const defaultSettings = { enabledEngines: defaultEngines.map(engine => engine.name), collapsed: false, keyboardShortcuts: true, macModifierType: 'command' }; const savedSettings = GM_getValue('searchEngineSettings'); if (!savedSettings) { log('未找到保存的设置,使用默认设置'); return defaultSettings; } try { const parsedSettings = typeof savedSettings === 'string' ? JSON.parse(savedSettings) : savedSettings; log('成功加载设置:', parsedSettings); return {...defaultSettings, ...parsedSettings}; } catch (e) { handleError(e, '解析设置'); return defaultSettings; } } catch (error) { handleError(error, '加载设置'); return { enabledEngines: defaultEngines.map(engine => engine.name), collapsed: false, keyboardShortcuts: true, macModifierType: 'command' }; } } // 保存设置 function saveSettings(settings) { try { log('保存设置:', settings); GM_setValue('searchEngineSettings', settings); return true; } catch (error) { handleError(error, '保存设置'); return false; } } // 获取当前搜索引擎和查询词 function getCurrentEngineAndQuery() { try { const url = window.location.href; let currentEngine = null; let query = ''; // 遍历搜索引擎进行匹配 for (const engine of defaultEngines) { // 创建正则表达式 const regexPattern = new RegExp(engine.matchPattern, 'i'); if (regexPattern.test(url)) { log(`匹配到搜索引擎: ${engine.name}`); currentEngine = engine; // 提取查询词 const urlObj = new URL(url); query = urlObj.searchParams.get(engine.queryParam) || ''; // 特殊处理DuckDuckGo if (engine.name === 'DuckDuckGo' && !query) { // 检查URL中是否包含q=参数(可能在hash中) if (url.includes('q=')) { const match = url.match(/[?&#]q=([^&#]*)/); if (match && match[1]) { query = decodeURIComponent(match[1]); } } } break; } } if (currentEngine) { log(`当前引擎: ${currentEngine.name}, 查询词: ${query}`); } else { log('未匹配到搜索引擎'); } return { currentEngine, query }; } catch (error) { handleError(error, '获取当前搜索引擎和查询词'); return { currentEngine: null, query: '' }; } } // 切换到指定搜索引擎 function switchToEngine(engine, query) { try { if (!query) { log('没有查询词,取消切换'); return; } // 将查询参数编码并替换到URL中 const encodedQuery = encodeURIComponent(query); const targetUrl = engine.url.replace('{query}', encodedQuery); log(`切换到 ${engine.name}, URL: ${targetUrl}`); // 导航到新的URL window.location.href = targetUrl; } catch (error) { handleError(error, '切换搜索引擎'); } } // 创建搜索引擎切换器UI function createSwitcherUI() { try { // 检查当前页面是否为搜索结果页 const { currentEngine, query } = getCurrentEngineAndQuery(); if (!currentEngine || !query) { log('未检测到搜索引擎或查询词,不创建UI'); return; } // 检查是否已存在搜索引擎切换器,如果存在则移除 let switcher = document.getElementById('search-engine-switcher'); if (switcher) { log('搜索引擎切换器已存在,移除旧的'); switcher.remove(); } // 获取设置 const settings = loadSettings(); // 获取启用的搜索引擎 const enabledEngines = getEnabledEngines(); // 创建搜索引擎切换器容器 switcher = document.createElement('div'); switcher.id = 'search-engine-switcher'; if (settings.collapsed) { switcher.classList.add('collapsed'); } // 创建标题栏 const header = document.createElement('div'); header.className = 'switcher-header'; // 创建标题 const title = document.createElement('div'); title.className = 'switcher-title'; title.textContent = '搜索引擎切换'; header.appendChild(title); // 创建按钮容器 const headerActions = document.createElement('div'); headerActions.className = 'header-actions'; // 创建设置按钮 const settingsButton = document.createElement('button'); settingsButton.className = 'settings-btn'; settingsButton.title = '设置'; settingsButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>'; settingsButton.addEventListener('click', function(e) { e.stopPropagation(); showSettingsPanel(); }); headerActions.appendChild(settingsButton); // 创建折叠/展开按钮 const collapseButton = document.createElement('button'); collapseButton.className = 'collapse-btn'; collapseButton.title = settings.collapsed ? '展开' : '折叠'; collapseButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"></polyline></svg>'; collapseButton.addEventListener('click', function(e) { e.stopPropagation(); // 切换折叠状态 switcher.classList.toggle('collapsed'); // 更新设置 const newSettings = {...settings, collapsed: switcher.classList.contains('collapsed')}; saveSettings(newSettings); // 更新按钮提示 this.title = newSettings.collapsed ? '展开' : '折叠'; }); headerActions.appendChild(collapseButton); header.appendChild(headerActions); switcher.appendChild(header); // 创建搜索引擎按钮容器 const engineContainer = document.createElement('div'); engineContainer.className = 'engine-container'; // 创建每个搜索引擎按钮 for (const engine of enabledEngines) { // 如果是当前搜索引擎,则跳过 if (currentEngine && engine.name === currentEngine.name) { continue; } // 创建按钮 const engineBtn = document.createElement('button'); engineBtn.className = 'engine-btn'; engineBtn.title = `在${engine.name}中搜索 "${query}"`; engineBtn.addEventListener('click', function() { switchToEngine(engine, query); }); // 创建图标 const img = document.createElement('img'); img.src = engine.icon; img.className = 'engine-icon'; img.alt = engine.name; img.onerror = function() { // 如果图标加载失败,使用文字缩写 this.outerHTML = `<div style="width:16px;height:16px;display:flex;align-items:center;justify-content:center;background:#f0f0f0;border-radius:3px;font-size:10px;font-weight:bold;">${engine.name.charAt(0)}</div>`; }; engineBtn.appendChild(img); // 添加搜索引擎名称 engineBtn.appendChild(document.createTextNode(engine.name)); // 如果启用快捷键,添加提示 if (settings.keyboardShortcuts) { const shortcutSpan = document.createElement('span'); shortcutSpan.className = 'shortcut'; shortcutSpan.textContent = `${modifierKey}${engine.shortcut}`; engineBtn.appendChild(shortcutSpan); } engineContainer.appendChild(engineBtn); } // 如果没有其他搜索引擎按钮,添加一个提示 if (engineContainer.children.length === 0) { const noEnginesMsg = document.createElement('div'); noEnginesMsg.textContent = '没有其他可用的搜索引擎'; noEnginesMsg.style.padding = '10px 0'; noEnginesMsg.style.color = '#888'; noEnginesMsg.style.fontSize = '12px'; noEnginesMsg.style.textAlign = 'center'; engineContainer.appendChild(noEnginesMsg); } switcher.appendChild(engineContainer); // 添加到页面 document.body.appendChild(switcher); // 添加点击事件,防止冒泡 switcher.addEventListener('click', function(e) { e.stopPropagation(); }); log('搜索引擎切换器UI已创建'); } catch (error) { handleError(error, '创建搜索引擎切换器UI'); } } // 显示设置面板 function showSettingsPanel() { try { log('显示设置面板'); // 获取当前设置 const settings = loadSettings(); // 创建设置覆盖层 const settingsOverlay = document.createElement('div'); settingsOverlay.className = 'settings-overlay'; // 创建设置容器 const settingsContainer = document.createElement('div'); settingsContainer.className = 'settings-container'; // 创建设置标题 const settingsHeader = document.createElement('div'); settingsHeader.className = 'settings-header'; settingsHeader.textContent = '搜索引擎切换工具设置'; settingsContainer.appendChild(settingsHeader); // 创建搜索引擎选择部分 const enginesSection = document.createElement('div'); enginesSection.className = 'settings-section'; const enginesTitle = document.createElement('div'); enginesTitle.className = 'section-title'; enginesTitle.textContent = '选择要显示的搜索引擎:'; enginesSection.appendChild(enginesTitle); const checkboxGroup = document.createElement('div'); checkboxGroup.className = 'checkbox-group'; // 添加每个搜索引擎的复选框 defaultEngines.forEach(engine => { const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.name = 'engine'; checkbox.value = engine.name; checkbox.checked = settings.enabledEngines.includes(engine.name); label.appendChild(checkbox); label.appendChild(document.createTextNode(` ${engine.name}`)); checkboxGroup.appendChild(label); }); enginesSection.appendChild(checkboxGroup); settingsContainer.appendChild(enginesSection); // 创建快捷键部分 const shortcutSection = document.createElement('div'); shortcutSection.className = 'settings-section'; const shortcutTitle = document.createElement('div'); shortcutTitle.className = 'section-title'; shortcutTitle.textContent = '快捷键设置:'; shortcutSection.appendChild(shortcutTitle); const shortcutCheckbox = document.createElement('label'); const shortcutInput = document.createElement('input'); shortcutInput.type = 'checkbox'; shortcutInput.name = 'keyboardShortcuts'; shortcutInput.checked = settings.keyboardShortcuts; shortcutCheckbox.appendChild(shortcutInput); shortcutCheckbox.appendChild(document.createTextNode(' 启用键盘快捷键')); shortcutSection.appendChild(shortcutCheckbox); // Mac特定选项 if (isMac) { const shortcutContent = document.createElement('div'); shortcutContent.style.marginTop = '10px'; shortcutContent.style.marginLeft = '20px'; shortcutContent.style.display = settings.keyboardShortcuts ? 'block' : 'none'; shortcutInput.addEventListener('change', function() { shortcutContent.style.display = this.checked ? 'block' : 'none'; }); const shortcutDescription = document.createElement('div'); shortcutDescription.textContent = '选择快捷键修饰键:'; shortcutContent.appendChild(shortcutDescription); const macOptions = document.createElement('div'); macOptions.className = 'mac-options'; // Command选项 const commandOption = document.createElement('label'); commandOption.className = 'mac-option'; const commandRadio = document.createElement('input'); commandRadio.type = 'radio'; commandRadio.name = 'macModifier'; commandRadio.value = 'command'; commandRadio.checked = settings.macModifierType === 'command'; commandOption.appendChild(commandRadio); commandOption.appendChild(document.createTextNode(' ⌘ (Command)')); // Option选项 const optionOption = document.createElement('label'); optionOption.className = 'mac-option'; const optionRadio = document.createElement('input'); optionRadio.type = 'radio'; optionRadio.name = 'macModifier'; optionRadio.value = 'option'; optionRadio.checked = settings.macModifierType === 'option'; optionOption.appendChild(optionRadio); optionOption.appendChild(document.createTextNode(' ⌥ (Option)')); macOptions.appendChild(commandOption); macOptions.appendChild(optionOption); shortcutContent.appendChild(macOptions); shortcutSection.appendChild(shortcutContent); } else { const shortcutDescription = document.createElement('div'); shortcutDescription.style.marginTop = '10px'; shortcutDescription.style.marginLeft = '20px'; shortcutDescription.style.display = settings.keyboardShortcuts ? 'block' : 'none'; shortcutDescription.textContent = '按下 Alt + 快捷键字母 可快速切换搜索引擎'; shortcutInput.addEventListener('change', function() { shortcutDescription.style.display = this.checked ? 'block' : 'none'; }); shortcutSection.appendChild(shortcutDescription); } settingsContainer.appendChild(shortcutSection); // 创建折叠选项 const collapseSection = document.createElement('div'); collapseSection.className = 'settings-section'; const collapseCheckbox = document.createElement('label'); const collapseInput = document.createElement('input'); collapseInput.type = 'checkbox'; collapseInput.name = 'collapsed'; collapseInput.checked = settings.collapsed; collapseCheckbox.appendChild(collapseInput); collapseCheckbox.appendChild(document.createTextNode(' 默认折叠')); collapseSection.appendChild(collapseCheckbox); settingsContainer.appendChild(collapseSection); // 创建按钮 const actions = document.createElement('div'); actions.className = 'settings-actions'; const cancelButton = document.createElement('button'); cancelButton.className = 'settings-button cancel-button'; cancelButton.textContent = '取消'; cancelButton.addEventListener('click', function() { settingsOverlay.remove(); }); const saveButton = document.createElement('button'); saveButton.className = 'settings-button save-button'; saveButton.textContent = '保存'; saveButton.addEventListener('click', function() { // 收集设置 const newSettings = { enabledEngines: Array.from( settingsContainer.querySelectorAll('input[name="engine"]:checked') ).map(checkbox => checkbox.value), keyboardShortcuts: settingsContainer.querySelector('input[name="keyboardShortcuts"]').checked, collapsed: settingsContainer.querySelector('input[name="collapsed"]').checked }; // Mac特定选项 if (isMac) { const macModifier = settingsContainer.querySelector('input[name="macModifier"]:checked'); newSettings.macModifierType = macModifier ? macModifier.value : 'command'; } // 保存设置 const success = saveSettings(newSettings); if (success) { settingsOverlay.remove(); // 刷新切换器界面 const switcher = document.getElementById('search-engine-switcher'); if (switcher) { switcher.remove(); } setTimeout(createSwitcherUI, 100); } }); actions.appendChild(cancelButton); actions.appendChild(saveButton); settingsContainer.appendChild(actions); settingsOverlay.appendChild(settingsContainer); document.body.appendChild(settingsOverlay); // 点击外部区域关闭设置面板 settingsOverlay.addEventListener('click', function(e) { if (e.target === settingsOverlay) { settingsOverlay.remove(); } }); log('设置面板已显示'); } catch (error) { handleError(error, '显示设置面板'); } } // 设置键盘快捷键 function setupKeyboardShortcuts() { try { const settings = loadSettings(); if (!settings.keyboardShortcuts) { log('快捷键功能已禁用'); return; } const { currentEngine, query } = getCurrentEngineAndQuery(); if (!query) { log('没有查询词,不设置快捷键'); return; } log('设置键盘快捷键'); document.addEventListener('keydown', function(e) { // 检查修饰键是否按下 let modifierPressed = false; if (isMac) { if (settings.macModifierType === 'command') { modifierPressed = e.metaKey; } else if (settings.macModifierType === 'option') { modifierPressed = e.altKey; } else { modifierPressed = e.metaKey; } } else { modifierPressed = e.altKey; } if (!modifierPressed) return; // 获取按下的键 const key = e.key.toUpperCase(); // 查找匹配的搜索引擎 const targetEngine = getEnabledEngines().find(engine => engine.shortcut && engine.shortcut.toUpperCase() === key && (!currentEngine || engine.name !== currentEngine.name) ); if (targetEngine) { e.preventDefault(); switchToEngine(targetEngine, query); } }); log('键盘快捷键已设置'); } catch (error) { handleError(error, '设置键盘快捷键'); } } // 设置DOM变化观察器 function setupMutationObserver() { try { log('设置MutationObserver开始'); // 创建一个观察器实例 const observer = new MutationObserver(function(mutations) { // 检查是否需要重新创建UI const switcher = document.getElementById('search-engine-switcher'); if (!switcher) { log('MutationObserver: UI不存在,重新创建'); createSwitcherUI(); } }); // 更频繁地观察DOM变化 const config = { childList: true, subtree: true }; observer.observe(document.body, config); // 定期检查UI是否存在 setInterval(() => { const switcher = document.getElementById('search-engine-switcher'); if (!switcher) { log('定期检查: UI不存在,重新创建'); createSwitcherUI(); } }, 3000); log('MutationObserver已增强设置'); } catch (error) { handleError(error, '设置MutationObserver'); } } // 添加菜单项 function setupUserMenu() { try { GM_registerMenuCommand('搜索引擎切换工具设置', showSettingsPanel); log('用户菜单已设置'); } catch (error) { handleError(error, '设置用户菜单'); } } // 初始化 function initialize() { try { log('开始初始化搜索引擎切换助手'); addStyles(); setupUserMenu(); setTimeout(createSwitcherUI, 100); setupKeyboardShortcuts(); setupMutationObserver(); log('初始化完成'); } catch (error) { handleError(error, '初始化'); } } // 立即执行初始化 initialize(); // 确保DOM加载后执行 if (document.readyState !== 'complete') { document.addEventListener('DOMContentLoaded', function() { setTimeout(createSwitcherUI, 300); }); } // 页面完全加载后再次执行 window.addEventListener('load', function() { setTimeout(createSwitcherUI, 500); }); })();