web_highlight

选中高亮!

目前为 2024-02-23 提交的版本。查看 最新版本

// ==UserScript==
// @name         web_highlight
// @namespace    http://tampermonkey.net/
// @version      0.1.2
// @description  选中高亮!
// @author       You
// @license      MIT
// @match        *://*/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...

    // 在网页中注入自定义的 CSS 样式
    GM_addStyle(`
        .menu_dialog {
          width: 40px;
          height: 40px;
          border-radius: 5px;
          position: absolute;
          background-color: red;
          cursor: pointer;
        }
        .pale_card {
          position: absolute;
          background-color: white;
          border: 1px solid gray;
          padding: 5px;
        }
        .pale_highlight_color {
          width: 10px;
          height: 10px;
          border-radius: 2px;
          cursor: pointer;
          margin-left: 3px;
          transition: width 0.3s, height 0.3s;
        }
        .pale_highlight_color:first-child {
          margin-left: 0;
        }
        .pale_highlight_color:hover {
          border: 2px solid;
        }
   `);

    const sites = {}
    const href = window.location.href;
    sites[href] = []
    let target = null // 选中的关键词的目标元素
    let menuDom = null // 菜单图标元素

    function findClosestChildWithKeyword(startingElement, keyword) {
        // 找到包含keyword的元素
        const queue = [startingElement];
        while (queue.length > 0) {
            const currentElement = queue.shift();
            if (currentElement.textContent.includes(keyword)) {
                return currentElement;
            }
            if (currentElement.children) {
                queue.push(...currentElement.children);
            }
        }
        return null; // 如果找不到含有关键词的子元素,则返回 null
    }

    function keyHighlight(key, color, keyTarget) {
        if (keyTarget) {
            // 根据元素查关键词
            key = keyTarget.innerText
            if (!sites[href].includes(key)) {
                sites[href].push(key)
            }
        } else {
            // 根据关键词找到元素
            keyTarget = findClosestChildWithKeyword(key)
        }
        // 设置背景
        const keyBackgroundSpan = document.createElement('span')
        keyBackgroundSpan.style.background = color
        keyBackgroundSpan.innerText = key
        keyTarget.innerHTML = ''
        keyTarget.appendChild(keyBackgroundSpan)
    }

    class ColorPale {
        // 参数
        colorList = ['#faa8a8', 'blue', 'green', 'yellow', 'orange']
        cardWidth = 20
        iconWidth = 40
        palePadding = 5
        colorMargin = 3

        // 以下参数仅供程序使用
        paleWidth = 0
        paleHeight = 0
        paleLeft = 0
        paleTop = 0
        pale = null
        isOnCard = false // 鼠标是否进入色卡

        initColorPale(menuDom) {
            this.paleWidth = this.colorList.length * this.cardWidth + this.palePadding * 2 + (this.colorList.length - 1) * this.colorMargin
            this.paleHeight = this.cardWidth + this.palePadding * 2
            this.paleLeft = parseInt(menuDom.style.left) - ((this.paleWidth - this.iconWidth) / 2)
            this.paleTop = parseInt(menuDom.style.top) + this.iconWidth

            this.pale = document.createElement('div')
            this.pale.className = 'pale_card'
            this.pale.style.width = this.paleWidth + 'px'
            this.pale.style.height = this.paleHeight + 'px'
            this.pale.style.left = this.paleLeft + 'px'
            this.pale.style.top = this.paleTop + 'px'
            this.pale.style.zIndex = '99';
            this.pale.style.display = 'none' // 隐藏

            this.colorList.forEach(color => {
                const colorCard = document.createElement('div')
                colorCard.className = 'pale_highlight_color'
                colorCard.style.width = this.cardWidth + 'px'
                colorCard.style.height = this.cardWidth + 'px'
                colorCard.style.backgroundColor = color
                colorCard.style.zIndex = '100';
                colorCard.addEventListener('click', (e) => {
                    keyHighlight(null, color, target)
                    e.stopPropagation();
                })
                colorCard.addEventListener('mouseup', (e) => {
                    // 阻止在设置色卡时触发清除函数
                    e.stopPropagation();
                })
                this.pale.appendChild(colorCard)
            })

            this.pale.addEventListener('mouseenter', (e) => {
                this.isOnCard = true
            })
            this.pale.addEventListener('mouseleave', (e) => {
                this.isOnCard = false
                this.closePale()
            })

            document.body.appendChild(this.pale)
            return Promise.resolve(this)
        }

        showPale(menuDom) {
            if (this.pale) {
                if (menuDom) {
                    this.paleLeft = parseInt(menuDom.style.left) - ((this.paleWidth - this.iconWidth) / 2)
                    this.paleTop = parseInt(menuDom.style.top) + this.iconWidth
                }
                this.pale.style.left = this.paleLeft + 'px'
                this.pale.style.top = this.paleTop + 'px'
                this.pale.style.display = 'flex'
                return Promise.resolve(this)
            } else if (menuDom) {
                return this.initColorPale(menuDom).then(Pale => {
                  Pale.pale.style.display = 'flex'
                  return Pale
                })
            }
        }

        closePale() {
            // 鼠标在色卡上不能关闭
            if (!this.isOnCard) {
                this.pale.style.display = 'none'
            }
        }
    }

    // 初始化
    const colorPale = new ColorPale

    // 滚动后重新加载高亮关键词
    window.addEventListener('scroll', highlight);

    let selectionTimeout;

    document.addEventListener('selectionchange', function() {
        // 移除之前添加的mouseup监听器
        document.removeEventListener('mouseup', handleMouseUp);

        // 添加新的mouseup监听器
        document.addEventListener('mouseup', handleMouseUp);
    });

    /**document.addEventListener('click', () => {
        // 监听选中消失的事件
        const selection = window.getSelection();
        if (selection.toString().length > 0) {
            // 没有选中
            clearData()
        }
    })*/

    function handleMouseUp(event) {
        // 删除之前的数据
        clearData()
        const selection = window.getSelection();
        if (selection.toString().length > 0) {
            // 用户选中了文本,可以在这里处理相应的逻辑
            target = event.target;
            console.dir(target, 'target');
            menuDom = document.createElement('div');
            menuDom.className = 'menu_dialog';
            menuDom.style.top = event.clientY + 'px'
            menuDom.style.left = event.clientX + 'px'
            menuDom.style.zIndex = '9999';
            menuDom.innerHTML = 'hello';

            menuDom.addEventListener('mouseup', (e) => {
                // 阻止在设置色卡时触发清除函数
                e.stopPropagation();
            })

            colorPale.showPale(menuDom).then(pale => {
                menuDom.addEventListener('mouseenter', (e) => {
                    console.log(e, '数据')
                    pale.showPale(menuDom)
                    // 鼠标移出时删除菜单
                    const handleMouseLeave = () => {
                        setTimeout(() => {
                            pale.closePale();
                            menuDom.removeEventListener('mouseleave', handleMouseLeave);
                        }, 300)
                    };
                    menuDom.addEventListener('mouseleave', handleMouseLeave)
                })
                document.body.appendChild(menuDom);
            })
        }
    }

    function clearData() {
        target = null
        if (menuDom) {
            document.body.removeChild(menuDom)
            menuDom = null
        }
    }

    function highlight() {
      sites[href].forEach(keyword => {
        const { word, color } = keyword

      })
    }

    function getSelectionElement() {
        const selection = window.getSelection();
        if (selection.rangeCount > 0) {
            const range = selection.getRangeAt(0);
            const startContainer = range.startContainer;
            const endContainer = range.endContainer;

            // 找到最接近的包含选中文本的父元素
            const closestParentElement = (startContainer.nodeType === 3) ? startContainer.parentNode : startContainer;
            // closestParentElement 就是包含选中文本的最接近的父元素
            return closestParentElement;
        }
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址