[js] 复制行级代码或图片时, 替换原始复制

操作&效果

默认复制行级代码

操作

  1. 光标放在行级代码中, 不需要选取文本
    image.png
  2. ctrl+c 复制
  3. 复制的内容就是行级代码的原始文本 image.png

其他场景都是默认的效果

  1. 选取部分文本
    image.png
  2. ctrl+c 复制
  3. 复制的内容就是默认的效果: 我这里是 image.png

默认复制原始图片

操作

  1. 选中图片
  2. ctrl+c 复制
  3. 复制的内容就是原始图片
  4. 相当于下面这个操作
    image.png

重要, 重要, 重要!!!

复制图片这个功能需要有复制块引用的快捷键, 我的快捷键是 shift+alt+c

image.png

如果你没有快捷键需要自行增加, 如果你的快捷键不是这个, 需要自行修改这部分代码

image.png

痛点

原本复制的是一个块链接文本, 类似于这样: ![image](assets/image-20241017134127-t1qqjbq.png)

但是我一般复制图片的时候, 都是从笔记里找到图片然后复制到其他地方, 那复制的就不能是链接, 应该是原始图片

重要备注

改之前, ctrl+c 默认复制的都是原始图片

这会导致一个问题, 原来在思源里复制粘贴一个图片, 这两个图片实际上都是块链接, 指向的是同一个文件, 磁盘只占用一个文件的大小

改之后, 相同的操作, 实际上是两份文件, 这两个图片是相同的, 有点浪费, 不过我笔记里一般不会有两个相同的图片, 所以可以接受这个效果

如果想达到之前的效果, 操作就比较复杂, 介意慎用, 自行注释掉: handle_cp_img

js 代码

(()=>{
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
// 判断是否选取了文本
function hasSelectedText() {
    const selection = window.getSelection();
    return selection && selection.toString().length > 0;
}
// 获取光标所在的元素
function getElementAtCursor() {
    const selection = window.getSelection();

    if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const startContainer = range.startContainer;

        // 如果是文本节点,获取其父元素
        const element = startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
        return element;
    }

    return null; // 如果没有选中内容或光标位置无效
}

// 处理复制行级代码
async function handle_cp_line_code(element) {
    if (!element) {
        return;
    }
    if (element.getAttribute('data-type') === 'code' && !hasSelectedText()) {
        // 如果是代码块,并且没有选中内容, 则复制代码块内容
        let content = element.textContent;
        if (content.startsWith('\u200B')) {
            content = content.slice(1); // 移除前面的零宽空格
        }
        await navigator.clipboard.writeText(content);
        await sleep(20)
    }
}

// 判断孩子节点是不是图片
function hasImageChild(element) {
    if (!element) {
        return false;
    }
    // 获取该元素的所有孩子节点
    const children = element.children;

    for (let i = 0; i < children.length; i++) {
        // 检查孩子节点的 data-type 属性
        if (children[i].getAttribute('data-type') === 'img') {
            return true; // 找到符合条件的孩子节点
        }
    }

    return false; // 没有符合条件的孩子节点
}
// 处理复制图片
function handle_cp_img(element) {
    if (!element) {
        return;
    }
    if (hasImageChild(element)) {
        let keyInit = {
            ctrlKey: false,
            altKey: true,
            shiftKey: true,
            key: 'C',
            keyCode: 67, // 不推荐使用,但某些情况下需要
            bubbles: true,
        }
        let keydownEvent = new KeyboardEvent('keydown', keyInit);
        element.dispatchEvent(keydownEvent);
        let keyUpEvent = new KeyboardEvent('keyup', keyInit);
        element.dispatchEvent(keyUpEvent);
    }
}

// 事件监听
document.addEventListener('keydown', async (event) => {
    if (event.ctrlKey && !event.shiftKey && !event.altKey && event.key === 'c') {
        // event.preventDefault(); // 防止快捷键默认行为
        let element = getElementAtCursor();
        // 判断是否需要复制行级代码, 并复制
        handle_cp_line_code(element);
        // 判断是否是图片, 并复制图片
        handle_cp_img(element);
    }
});

})()

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22926 引用 • 92174 回帖 • 1 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    85 引用 • 516 回帖
1 操作
EmberSky 在 2024-11-08 14:52:25 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • 感谢大佬的代码片段,非常好用

  • 其他回帖
  • MaxYang

    感谢,提醒大家一下,如果用的 mac 代码里面的 event.ctrlKey 需要改成 event.metaKey

  • 直接在原文上改吧,这个零宽空格在文本中显示不出来,等我放在命令行中运行的时候才发现多了一个空格,怪不得一直报错 😂

  • EmberSky 1 评论

    复制行级代码时有 bug, 前缀会多一个空白字符

    需要将 handle_cp_line_code 函数修改成下面这个

    // 处理复制行级代码
    async function handle_cp_line_code(element) {
        if (!element) {
            return;
        }
        if (element.getAttribute('data-type') === 'code' && !hasSelectedText()) {
            // 如果是代码块,并且没有选中内容, 则复制代码块内容
            let content = element.textContent;
            if (content.startsWith('\u200B')) {
                content = content.slice(1); // 移除前面的零宽空格
            }
            await navigator.clipboard.writeText(content);
            await sleep(20)
        }
    }
    
    1 回复
    已更新到帖子的代码上
    EmberSky