【实用脚本】油猴脚本:网页阅读时的选中高亮显示与擦除

起因

很久之前在看文章的时候习惯于PDF格式的笔者总是想要用高亮勾画自己认为重要的内容,奈何网页不是pdf,没有那么方便的东西。
知道接触到油猴脚本,突然觉得自己可以搞一下,但笔者js技术力太菜,又不想花费很多时间在这上面,于是一拖再拖。直到最近AI大火,觉得自己可以试着搞一下了,就通过Bing Chat搞出来了,希望可以为有类似烦恼的朋友提供一个开箱即用的参考。

描述

  • 浏览器: Edge

  • 油猴: TamperMonkey

  • 使用方式:

    • 添加高亮:按住Ctrl,同时鼠标选中网页文本即可高亮显示。
    • 删除高亮:按住Alt,鼠标左键点击高亮文本即可删除高亮。
  • 亮点:
    首先,这个脚本可以让你在任何网页上高亮文本。无论你是在阅读新闻、研究报告,还是学习教程,你都可以使用这个工具来标记重要的信息。

    其次,这个脚本还有一个便笺功能。当你高亮文本时,这个脚本会自动将高亮的文本添加到便笺中。这样,你就可以在一个地方查看所有的高亮文本,而不需要在页面上下滚动寻找。

    最后,该脚本存在复制和清空按钮,可以一键复制所有Markdown形式的高亮文本内容或清楚当前所有的高亮。

  • 添加方式:

    1. 找到添加了油猴脚本的右上角,选择“添加新脚本”。如下图
      位置示意图

    2. 进入界面后,将原本的初始内容删除,将下述代码粘贴( 2024.01.04 更新):

// ==UserScript==
// @name         HighLighter
// @namespace    http://tampermonkey.net/
// @version      0.3.0
// @description  当按住键盘的Ctrl键并使用鼠标选中部分网页文字时,将对应文字的背景高亮显示(例如明黄色),当按住键盘的Alt键并使用鼠标左键点击部分网页文字时,删除对应高亮
// @author       Baxkiller with Bing AI & Copilot
// @match        *://*/*
// @grant        none
// ==/UserScript==

// 定义一个高亮颜色
var highlightColor = "yellow";
var highlight_cnt=0;
var highlight_limit=100;
var created_note = false;
// 创建用于暂存高亮内容的数组
var highlightContents = [];
var note;

// 定义和创建网页右侧便笺
class Note {
    constructor() {
        this.wrapper = document.createElement('div');
        this.wrapper.style.position = 'fixed';
        this.wrapper.style.right = '0';
        this.wrapper.style.top = '20%'; // 垂直居中
        this.wrapper.style.width = '200px';
        this.wrapper.style.height = '70vh'; // 自动高度
        this.wrapper.style.backgroundColor = 'rgba(240, 240, 240, 0.8)';  // 设置背景颜色为略微透明的灰色
        this.wrapper.style.padding = '10px';
        this.wrapper.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)'; // 添加阴影
        this.wrapper.style.borderRadius = '18px'; // 添加圆角
        this.wrapper.style.zIndex = '9999'; // 置于顶层

        this.note = document.createElement('div');
        this.note.style.overflow = 'auto';
        this.note.style.height = '92%'; // 最大高度60%的视口高度
        this.wrapper.appendChild(this.note);

        document.body.appendChild(this.wrapper);

        this.addCopyButton();
        this.addClearButton();
    }

    addText(text) {
        // console.log(text);
        this.note.innerHTML += text + '<br>';
    }

    addHightLightNode(node) {
        var text = node.textContent;
        var parent = node.parentNode;
        var markdownText = text;

        if (parent.tagName === 'H1') {
            markdownText = '# ' + text;
        } else if (parent.tagName === 'H2') {
            markdownText = '## ' + text;
        } else if (parent.tagName === 'H3') {
            markdownText = '### ' + text;
        } else if (parent.tagName === 'P') {
            markdownText = text;
        } else if (parent.tagName === 'SPAN') {
            markdownText = text;
        } else if (parent.tagName === 'A') {
            markdownText = '[' + text + '](' + parent.href + ')';
        } else if (parent.tagName === 'IMG') {
            markdownText = '![' + parent.alt + '](' + parent.src + ')';
        } else if (parent.tagName === 'LI') {
            markdownText = '- ' + text;
        } else if (parent.tagName === 'UL') {
            markdownText = '- ' + text;
        } else if (parent.tagName === 'OL') {
            markdownText = '1. ' + text;
        }

        this.addText(markdownText);
    }

    addCopyButton() {
        var copyButton = document.createElement('button');
        copyButton.innerText = 'Copy';
        copyButton.style.width = '100%'; // 与便笺同宽
        copyButton.style.height = '6%';
        copyButton.style.backgroundColor = '#007BFF'; // 蓝色背景
        copyButton.style.color = '#FFFFFF'; // 白色文字
        copyButton.style.border = 'none'; // 无边框
        copyButton.style.padding = '10px';
        copyButton.style.cursor = 'pointer'; // 鼠标悬停时变为手形
        copyButton.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)'; // 添加阴影
        copyButton.style.borderRadius = '18px'; // 添加圆角
        copyButton.style.zIndex = '9999';

        copyButton.onclick = () => {
            console.log("copy button clicking");
            navigator.clipboard.writeText(this.note.innerText).then(function() {
                console.log('复制成功');
            }, function(err) {
                console.error('复制失败', err);
            });
            console.log("copy button clicked");

        };
        this.wrapper.appendChild(copyButton);
    }

    addClearButton() {
        var clearButton = document.createElement('button');
        clearButton.innerText = 'Clear';
        clearButton.style.width = '100%'; // 占据一半宽度
        clearButton.style.height = '6%';
        clearButton.style.backgroundColor = '#dc3545'; // 红色背景
        clearButton.style.color = '#FFFFFF'; // 白色文字
        clearButton.style.border = 'none'; // 无边框
        clearButton.style.padding = '10px';
        clearButton.style.cursor = 'pointer'; // 鼠标悬停时变为手形
        clearButton.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)'; // 添加阴影
        clearButton.style.borderRadius = '18px'; // 添加圆角
        clearButton.style.zIndex = '9999'; 

        clearButton.onclick = () => {
            console.log("clear button clicking");
            this.note.innerHTML = ''; // 清除所有文本
            console.log("clear button clicked");
        };
        this.wrapper.appendChild(clearButton);
    }
}

function highlightNode(node, startOffset, endOffset) {
    if (highlight_cnt > highlight_limit) {
        return false;
    }
    var highlight_block = document.createElement("highlight");
    highlight_block.style.backgroundColor = highlightColor;
    var nodeRange = document.createRange();
    nodeRange.setStart(node, startOffset !== undefined ? startOffset : 0);
    nodeRange.setEnd(node, endOffset !== undefined ? endOffset : node.nodeValue.length);
    nodeRange.surroundContents(highlight_block);

    if (!created_note) {
        note = new Note();
        created_note = true;
    }
    note.addHightLightNode(highlight_block);

    highlight_cnt++;
    return true;
}

function highlightRange(range) {
    var commonAncestor = range.commonAncestorContainer;
    var startNode = range.startContainer;
    var endNode = range.endContainer;

    var treeWalker = document.createTreeWalker(commonAncestor, NodeFilter.SHOW_TEXT);
    var currentNode = treeWalker.currentNode;

    var inRange = false;
    while (currentNode) {
        if (currentNode === startNode) {
            inRange = true;
        }
        if (inRange && currentNode.nodeValue.trim() !== '') {
            var startOffset = (currentNode === startNode) ? range.startOffset : 0;
            var endOffset = (currentNode === endNode) ? range.endOffset : currentNode.nodeValue.length;
            highlightContents.push({
                node: currentNode,
                startOffset: startOffset,
                endOffset: endOffset
            });
        }
        if (currentNode === endNode) {
            break;
        }
        currentNode = treeWalker.nextNode();
    }
}

function highlightSelection() {
    var selection = window.getSelection();
    if (selection.rangeCount > 0) {
        var range = selection.getRangeAt(0);
        var isHighlighted = range.startContainer.parentNode.style.backgroundColor === highlightColor;
        if (isHighlighted) return;

        highlightRange(range);
        highlightContents.forEach(function (highlightContent) {
            highlightNode(highlightContent.node, highlightContent.startOffset, highlightContent.endOffset);
        });

        // 一次性选中内容的后面添加换行符
        if (highlightContents.length > 0) {
            note.addText('<br>');
        }

        // 直接清空,防止溢出
        highlightContents.length = 0;
        highlightContents = [];

        selection.removeAllRanges();
    }
}

// 定义一个函数,用于取消高亮选中的文字
function unhighlightSelection(event) {
    // 获取鼠标点击的元素
    var element = event.target;
    var isHighlighted = element.tagName === "HIGHLIGHT" && element.style.backgroundColor === highlightColor;
    if (!isHighlighted){
        // console.log(element.tagName);
        // console.log(element.style.backgroundColor);
        return;
    }

    // 将higlilight元素替换为它textContent的内容
    var highlight_block = element;
    var text = highlight_block.textContent;
    var textNode = document.createTextNode(text);
    highlight_block.parentNode.replaceChild(textNode, highlight_block);
}

// 监听键盘按下事件
document.addEventListener("keydown", function (event) {
    // 判断是否按下了Ctrl键或Alt键
    if (event.ctrlKey || event.altKey) {
        // 根据按下的键,选择对应的函数作为鼠标事件的监听器
        var handler = event.ctrlKey ? highlightSelection : unhighlightSelection;
        // 监听鼠标事件,调用对应函数
        if (event.ctrlKey) {
            // 如果按下了Ctrl键,则监听鼠标松开事件,用于高亮选中的文字
            document.addEventListener("mouseup", handler);
        } else {

            document.addEventListener("mousedown", handler);
        }
    }
});

// 监听键盘松开事件
document.addEventListener("keyup", function (event) {
    // 判断是否松开了Ctrl键或Shift键
    if (event.key === "Control" || event.key === "Alt") {
        // 根据松开的键,选择对应的函数作为鼠标事件的监听器
        var handler = event.key === "Control" ? highlightSelection : unhighlightSelection;
        // 移除鼠标事件的监听器
        if (event.key === "Control") {

            document.removeEventListener("mouseup", handler);
        } else {

            document.removeEventListener("mousedown", handler);
        }
    }
});

  1. Ctrl+S 保存,退出编辑页面后随便打开一篇博文或网页,将右上角的HighLighter脚本打开,即可使用。

其他

如果您在使用过程中有任何问题或者建议,可以在本文下留言或私信。
或者,如果您也有其他关于本脚本或者相关的脚本创建/使用/改进想法,欢迎与我一起参与开发/维护新的脚本。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值