Greasy Fork

来自缓存

Greasy Fork is available in English.

最简洁的划线翻译

网页不认识的单词,划线点击按钮,立马得到结果

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         最简洁的划线翻译
// @namespace    http://tampermonkey.net/
// @version      2025-4-8
// @description  网页不认识的单词,划线点击按钮,立马得到结果
// @author       aipinky
// @include      *
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @run-at document-end
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    // 插入 CSS 样式
    const style = document.createElement('style');
    style.textContent = `
       .ptext {
            position: fixed;
            width: 250px;
            background-color: hwb(0 97% 2%);
            border-radius: 10px;
            display: none;
            padding-left: 10px;
            border: 2px solid #cecbcb;
        }

       #lp .pfixed,
       #lp .pdel {
            position: absolute;
            width: 15px;
            height: 15px;
            border-radius: 50%;
            border: 0;
        }

        #lp a {
            float: left;
        }

        #lp {
            height:20px;
            width:100%;
            display: flex;
            align-items: center;
            margin-top:5px;
        }

       #lp .pdel {
            font-size: 13px;
            color: #fff;
            margin-right: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: red;
            right:40px
        }

       #lp .pfixed {
            margin-right: 40px;
            background-color: greenyellow;
            right:-10px;
        }

        .pdata {
            margin-top: 5px;
            margin-bottom: 10px;
            width: 90%;
            padding: 10px;
            line-height: 1.5;
            font-size: 15px;
            overflow: hidden;
            background-color: #fff;
        }

        .pimg {
            width: 25px;
            height: 25px;
            border-radius: 50%;
            background-color: red;
            background: url(https://i.postimg.cc/3xcgdvXs/lovetranslate-resized.png) no-repeat center/cover;
            border: 0;
            display: none;
            position: fixed;
        }

        * {
        user-select: auto !important;
    }
    `;
    document.head.appendChild(style);


    // 动态加载 axios
    const script = document.createElement('script');
    script.src = 'https://unpkg.com/axios/dist/axios.min.js';
    script.onload = function() {
        initScript(); // axios 加载完成后初始化脚本
    };
    document.head.appendChild(script);

    function initScript() {
        // 创建 HTML 结构
        const html = `
            <div class="ptext">
                <p id="lp"><a href="#">API(有道)</span>
                    <a href="#" class="pfixed"></a>
                    <a href="#" class="pdel">X</a>
                     <div class="clearfix"></div>
                </p>
                <div name="textarea" id="" class="pdata"></div>
            </div>
            <a href="#" onclick="return false;" class="pimg"></a>
        `;
        document.body.insertAdjacentHTML('beforeend', html);

        // 获取元素
        const text = document.querySelector('.ptext');
        const dataText = document.querySelector('.pdata');
        const delBtn = document.querySelector('#lp .pdel');
        const fixed = document.querySelector('#lp .pfixed');
        const imgBtn = document.querySelector('.pimg');

        // 关闭按钮,关闭窗口
        delBtn.addEventListener('click', () => {
            ['click', 'mousedown', 'mouseup', 'mousemove', 'contextmenu'].forEach(eventType => {
                text.addEventListener(eventType,preEvent)});
            dataText.innerHTML = '';
            text.style.display = 'none';
            flag = false;
            fixed.style.backgroundColor = 'greenyellow';
            text.style.cursor = '';
        });

        // 点击固定按钮,任意拖拽位置
        let isDragging = false; // 是否正在拖拽
        let offsetX, offsetY; // 鼠标相对于盒子左上角的偏移量
        let flag = false;
        function preEvent(event) {
            event.preventDefault();
            event.stopPropagation();
        }

        fixed.addEventListener('click', () => {
            // 定义事件处理函数
            // 禁用所有鼠标事件
            ['click', 'mousedown', 'mouseup', 'mousemove', 'contextmenu'].forEach(eventType => {
                text.addEventListener(eventType,preEvent)});

            if (flag === false) {
                flag = true;
                fixed.style.backgroundColor = 'pink';
                text.style.cursor = 'move';
            } else {
                flag = false;
                fixed.style.backgroundColor = 'greenyellow';
                text.style.cursor = '';
            }
        });

        // 鼠标按下时开始拖拽
        text.addEventListener('mousedown', function(event) {
            isDragging = true;

            // 计算鼠标相对于盒子左上角的偏移量
            offsetX = event.clientX - text.offsetLeft;
            offsetY = event.clientY - text.offsetTop;

            // 改变鼠标样式
            if(fixed.style.backgroundColor === 'pink'){
                ['click', 'mousedown', 'mouseup', 'mousemove', 'contextmenu'].forEach(eventType => {
                    text.removeEventListener(eventType, preEvent);
                });
                text.style.cursor = 'grabbing';
            }

        });

        // 鼠标移动时更新盒子位置
        document.addEventListener('mousemove', function(event) {
            if (isDragging && fixed.style.backgroundColor === 'pink') {
                // 计算盒子的新位置
                const newLeft = event.clientX - offsetX;
                const newTop = event.clientY - offsetY;

                // 更新盒子的位置
                text.style.left = `${newLeft}px`;
                text.style.top = `${newTop}px`;
            }
        });
        let selection;
        let mouseX, mouseY;
        // 鼠标松开时停止拖拽
        document.addEventListener('mouseup', function(event) {
            isDragging = false;
            // 恢复鼠标样式
            if(fixed.style.backgroundColor === 'pink'){
                text.style.cursor = 'move';
            }else{
                text.style.cursor = '';
            }


            // 检查是否有选中的文本
            if (selection && !text.contains(event.target) && text.style.display === 'none') {
                const mous1 = event.clientY;
                const mous2 = event.clientX;
                imgBtn.style.top = `${mous1}px`;
                imgBtn.style.left = `${mous2}px`;
                imgBtn.style.display = 'block';
            } else {
                console.log('没有选中文本');
            }

        });


        // 监听 selectionchange 事件
        document.addEventListener('selectionchange', function() {
            // 获取当前选中的文本
            if(!text.contains(event.target)){
                selection = window.getSelection().toString();
            }
        });

        // 点击图片按钮,显示文本框
        imgBtn.addEventListener('click', () => {
            getWhere();
            text.style.display = 'block';
            getText(selection)
                .then(data => {
                dataText.innerHTML = data;
            })
                .catch(error => {
                dataText.innerHTML = error;
            });
            imgBtn.style.display = 'none';
        });

        function getWhere() {
            document.addEventListener('mouseup', function() {
                const selection = window.getSelection();

                // 检查是否有选中的文本
                if (selection.toString().length > 0 && !text.contains(event.target) && text.style.display === 'none') {
                    // 获取选中的范围
                    const range = selection.getRangeAt(0);

                    // 获取选中文本的长度
                    const textLength = selection.toString().length;

                    // 计算中间位置的索引
                    const middleIndex = Math.floor(textLength / 2);

                    // 创建一个新的 Range,用于定位中间位置
                    const middleRange = document.createRange();
                    middleRange.setStart(range.startContainer, range.startOffset + middleIndex);
                    middleRange.setEnd(range.startContainer, range.startOffset + middleIndex + 1);

                    // 获取中间位置的边界框
                    const middleRect = middleRange.getBoundingClientRect();

                    // 计算中间位置的坐标
                    const middleX = middleRect.left + middleRect.width / 2;
                    //const middleY = middleRect.top + middleRect.height / 2;
                    //const mouseY = event.clientY;
                    const mouseY = middleRect.top + middleRect.height / 2;


                    // 获取窗口的高度和宽度
                    const windowHeight = window.innerHeight;
                    const windowWidth = window.innerWidth;

                    // 计算鼠标距离窗口底部的距离
                    let fromBottom = windowHeight - mouseY;
                    let formLeft = windowWidth - middleX;
                    if (middleX > 150 && middleX < windowWidth - 150) {
                        text.style.left = `${middleX - 150}px`;
                        if (fromBottom > 100) {
                            text.style.top = `${mouseY + 18}px`;
                        } else {
                            text.style.bottom = `${fromBottom + 18}px`;
                        }
                    } else if (middleX >= windowWidth - 150) {
                        text.style.left = `${windowWidth - 350}px`;
                        if (fromBottom > 100) {
                            text.style.top = `${mouseY + 18}px`;
                        } else {
                            text.style.bottom = `${fromBottom + 18}px`;
                        }
                    } else {
                        if (fromBottom > 100) {
                            let newMiddleX = 150 - middleX;
                            text.style.top = `${mouseY + 18}px`;
                            text.style.left = `${middleX - 140 + newMiddleX}px`;
                        } else {
                            let newMiddleX = 150 - middleX;
                            text.style.bottom = `${fromBottom + 18}px`;
                            text.style.left = `${middleX - 140 + newMiddleX}px`;
                        }
                    }
                }
            });
        }

        //!text.contains(event.target) || getWhere();
        getWhere()
        // 监听 document 上的 mousedown 事件
        document.addEventListener('mousedown', function(event) {
            if (!imgBtn.contains(event.target)) {
                imgBtn.style.display = 'none';
            }

            // 检查点击的目标是否是盒子或其子元素
            if (!text.contains(event.target)) {
                text.style.display = 'none';
                flag = false;
                fixed.style.backgroundColor = 'greenyellow';
                text.style.cursor = '';
            } 
        });

        // 请求函数
        function getText(param) {
            return axios({
                url: 'https://v.api.aa1.cn/api/api-fanyi-yd/index.php',
                method: 'get',
                params: {
                    msg: param,
                    type: 3
                }
            })
                .then(re => {
                // 使用正则表达式匹配 {} 里面的内容
                const matches = re.data.match(/\{([^}]+)\}/g);

                if (matches) {
                    // 提取内容并去掉 {}
                    const results = matches.map(match => match.replace(/[{}]/g, ''));
                    // 原始字符串
                    const str = results[1];
                    // 修复字符串格式
                    const fixedStr = `{${str.replace(/)/g, ')')}}`; // 将中文括号替换为英文括号,并添加外层 {}

                    // 转换为对象
                    const obj = JSON.parse(fixedStr);
                    return obj.text;
                } else {
                    return '没有找到 {} 里面的内容';
                }
            })
                .catch(err => {
                console.log(err.data);
                throw err.data;
            });
        }
    }
    document.body.style.userSelect = 'text';
    document.body.style.webkitUserSelect = 'text';
    document.body.style.mozUserSelect = 'text';
    document.body.style.msUserSelect = 'text';
})();