划词翻译(增强版)

单击页面单词,详细中文释义,支持音标,适配移动端,百度翻译+有道发音服务。

目前为 2024-11-16 提交的版本。查看 最新版本

// ==UserScript==
// @name         划词翻译(增强版)
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  单击页面单词,详细中文释义,支持音标,适配移动端,百度翻译+有道发音服务。
// @author       ChatGPT
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    const popup = document.createElement('div');
    popup.style.position = 'absolute';
    popup.style.backgroundColor = '#fdfdfd';
    popup.style.border = '1px solid #ccc';
    popup.style.borderRadius = '8px';
    popup.style.padding = '15px';
    popup.style.fontSize = '16px';
    popup.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
    popup.style.zIndex = '9999';
    popup.style.display = 'none';
    popup.style.width = '90%';
    popup.style.maxWidth = '600px';
    popup.style.wordWrap = 'break-word';
    popup.style.lineHeight = '1.5';
    popup.style.whiteSpace = 'normal';
    popup.style.wordBreak = 'break-word';
    popup.style.left = '50%';
    popup.style.transform = 'translateX(-50%)';
    document.body.appendChild(popup);

    function hidePopup() {
        popup.style.display = 'none';
    }

    function showPopup(word, content, x, y) {
        const phonetic = content.phonetic ? `<div><strong>音标:</strong> [${content.phonetic}]</div>` : '';
        const meanings = content.meanings.map(meaning => `<li>${meaning}</li>`).join('');

        popup.innerHTML = `
            <div><strong>单词:</strong> ${word}</div>
            ${phonetic}
            <div><strong>释义:</strong><ul>${meanings}</ul></div>
        `;
        popup.style.top = `${y + 10}px`;
        popup.style.display = 'block';
    }

    function fetchTranslation(word) {
        const apiURL = `https://fanyi.baidu.com/sug`;
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: apiURL,
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                data: `kw=${encodeURIComponent(word)}`,
                onload: function (response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data && data.data && data.data.length > 0) {
                            const result = data.data[0];
                            resolve({
                                phonetic: result.k || null,
                                meanings: data.data.map(item => item.v)
                            });
                        } else {
                            reject(new Error('翻译结果为空'));
                        }
                    } catch (error) {
                        reject(error);
                    }
                },
                onerror: function () {
                    reject(new Error('查询失败'));
                }
            });
        });
    }

    function playAudio(word) {
        const audio = new Audio(`https://dict.youdao.com/dictvoice?type=0&audio=${encodeURIComponent(word)}`);
        audio.play();
    }

    function getWordAtPoint(x, y) {
        const range = document.caretRangeFromPoint(x, y);
        if (range && range.startContainer.nodeType === Node.TEXT_NODE) {
            const textNode = range.startContainer;
            const offset = range.startOffset;
            const text = textNode.nodeValue;

            const before = text.substring(0, offset).match(/[\w\u4e00-\u9fa5]+$/);
            const after = text.substring(offset).match(/^[\w\u4e00-\u9fa5]+/);

            return (before ? before[0] : '') + (after ? after[0] : '');
        }
        return null;
    }

    document.addEventListener('click', (event) => {
        const word = getWordAtPoint(event.clientX, event.clientY);
        if (word) {
            const x = event.pageX;
            const y = event.pageY;

            showPopup(word, { meanings: ['加载中...'] }, x, y);

            fetchTranslation(word).then(content => {
                showPopup(word, content, x, y);
                playAudio(word);
            }).catch(() => {
                showPopup(word, { meanings: ['查询失败'] }, x, y);
            });
        } else {
            hidePopup();
        }
    });

    document.addEventListener('click', (e) => {
        if (!popup.contains(e.target)) {
            hidePopup();
        }
    });
})();