如何实现掘金复制自由-从0到1搭建chrome插件

我们在从掘金复制内容时,发现复制完的内容后面每次都拼接上一些东西,例如:



作者:***
链接:https://juejin.cn/post/***
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

看到这个,每次都在想这是如何实现的呢?

刚开始以为很复杂,以为要给document或者div上绑定keydownkeyup的事件,后来搞了一波,发现并不需要。这里还有个坑,就是div上绑定的keydownkeyup不生效,如何让这个生效可以自行搜索一下。

复制

直奔主题,需要实现这个很简单,只需要监听浏览器自带的copy就可以



<body>
    <div class="wrap">
        <p>我和我亲爱的祖国</p>
        <p>一刻也不能分割</p>
        <div class="copy">
           <p onclick="handleCopy(false)" class="btn">复制内容</p>
           <div id="copy-area">
            <p>我们的祖国是花园</p>
            <p>花园里的花朵真鲜艳</p>
           </div>
        </div>
    </div>
<script>
    const handleCopy = ()=>{
        const copyText = document.getElementById('copy-area')
        navigator.clipboard.writeText(copyText.innerText);
    }
    document.addEventListener('copy',(event)=>{
         // 获取用户选择的文本
         var selection = window.getSelection().toString();
         if(selection){
            const appendText = '\n\n ~~~我是后缀小尾巴~~~'
            // 获取剪贴板对象
            var clipboardData = event.clipboardData || window.clipboardData;
            // 设置剪贴板的内容为选择的文本加上拼接的文字
            clipboardData.setData("text", selection + appendText);
            // 阻止默认的复制行为
            event.preventDefault();
         }
    })

</script>

handleCopy中也有一个坑,就是在百度时一般提供的是以下的写法

function myFunction() {
  /* 获取文本内容 */
  var copyText = document.getElementById("myInput");

  /* 选择复制内容 */
  copyText.select();
  copyText.setSelectionRange(0, 99999); /* 为移动设备设置 */

   /* 复制内容到文本域 */
  navigator.clipboard.writeText(copyText.value);


  /* 弹出已复制的内容 */
  alert("复制的文本为: " + copyText.value);
}

这里的坑就时copyText.select()不生效,可以查下,select**HTMLInputElement.select()  方法选中一个 <textarea> 元素或者一个带有 text 字段的 <input> 元素里的所有内容

我们这里要复制的是div的内容,所以直接将innerText的值给到剪切板就行

改写复制剪切板

在复制掘金的内容时,大多数情况下都会带一些作者信息之类的内容,现在既然已经了解了复制相关的知识,想着能不能自己写一个插件,当开启这个插件时,就自动把掘金上复制的内容中把作者这些的信息手动删除呢

创建目录
创建工作目录
mkdir demo-plugin
创建清单文件 manifest.json
{



    "name":"demo-plugin",  // 插件名称
    "version":"1.0",       // 版本
    "description":"demo plugin",  // 描述
    "manifest_version":3       // 清单版本,有2和3,2在2023年已经被移除
}

本地导入

在chrome浏览器中输入chrome://extensions/

image.png

选择加载已解压的扩展程序,选择demo-plugin

image.png

可以看到插件已经被加载进来了,为了便于开发,我们可以将其固定在操作栏位

image.png

设置图标

图标是默认的,我们可以设置一下图标

我从iconfont上下载了一些icon,新建images目录,将图片放置到此目录下,修改manifest.json

{



    "name":"demo-plugin",


    "version":"1.0",


    "description":"demo plugin",


    "manifest_version":3,


    "icons":{


        "16": "images/clipboard_16.png",


        "32": "images/clipboard_32.png",


        "48": "images/clipboard_48.png",


        "64": "images/clipboard_48.png",


        "128": "images/clipboard_128.png"


    }
}

重新加载插件

image.png

可以看到我们设置的图标已经生效了

添加popup

我的设想是在点击图标时弹出一个popup,popup中有选项,选项中是让我选择是否要修改掘金内容的剪切板。我们在选完之后要将内容存储起来,存储的话,用到了storage,popup用到了action,所以需要先修改manifest.json

{



    "name":"demo-plugin",


    "version":"1.0",


    "description":"demo plugin",


    "manifest_version":3,


    "icons":{


        "16": "images/clipboard_16.png",


        "32": "images/clipboard_32.png",


        "48": "images/clipboard_48.png",


        "64": "images/clipboard_48.png",


        "128": "images/clipboard_128.png"


    },

    "permissions": ["storage"],
    "action":{

        "default_popup":"popup.html"

    }
}

创建popup.html

<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="popup.css">
  </head>
  <body>
    <div class="clip-wrap" id="senga-clipboard"></div>
    <button  id="btn" class="btn">确定</button>
    <script src="popup.js"></script>
  </body>
</html>

popup.css

.clip-item {
  margin:10px;
  display: flex;
  align-items: center;
}
.clip-item input {
    margin-right: 10px;
}
.clip-item span {
    white-space: nowrap;
}
.btn {
    margin:10px 0px 10px 40px;
    border:1px solid blue;
    border-radius:8px;
    color:blue;
    padding:5px 10px;
    background-color: transparent;
}

popup.js

// 定义列表内容
const lists = [
    {
        checked: true,
        title: '修改掘金剪切板',
        id: 'juejin'
    }
]




const init = () => {
    chrome.storage.local.get(['clipfilter']).then((result) => {
        console.log(11, result.clipfilter)
        lists[0].checked = result.clipfilter
        insertList()
    });
}



init()

const handleInput = () => {
    const iptLists = document.getElementsByClassName("ipt");
    Array.from(iptLists).map(item => {
        item.addEventListener("change", (e) => {
            const idx = e.target.dataset.id
            lists[idx].checked = e.target.checked
        });
    })
}

// 获取剪切板容器
const clip = document.getElementById("senga-clipboard")
// 添加选项
const insertList = () => {
    let str = ''
    lists.forEach((item, idx) => {
        const input = item.checked ? `<input type="checkbox" checked class="ipt" data-id=${idx} />` : `<input type="checkbox" class="ipt" data-id=${idx} />`
        str += `<section class="clip-item">` + input +
            `<span>${item.title}</span>
            </section>`
    })
    clip.innerHTML = str
    handleInput()
}


// 通过ID找到按钮
const button = document.getElementById("btn");

// 注册按钮点击回调函数
button.addEventListener("click", async () => {
    // 将list中checked为true的存储到chrome中
    console.log('set', lists[0].checked)
    chrome.storage.local.set({ clipfilter: lists[0].checked }).then(() => {
        // 关闭popup
        window.close()
    });
});




重新加载插件后可以看到如下的截图

image.png

如何对popup.js进行调试呢,可以插件右击选择审查弹出内容

image.png

可以在弹出的控制台查看storage是否生效

坑:这里有个坑,就是在在html文件中不可以直接定义函数

例如:我们是在popup.js中获取按钮并给按钮绑定事件,按照常规写法,我们可以直接在按钮上写上onclick="test",不支持这样的写法,具体是啥报错,可以自己试一下

操作剪切板

操作剪切板,需要剪切板的权限,具体的操作用content_scripts,修改manifest.json

{



    "name":"demo-plugin",


    "version":"1.0",


    "description":"demo plugin",


    "manifest_version":3,


    "icons":{


        "16": "images/clipboard_16.png",


        "32": "images/clipboard_32.png",


        "48": "images/clipboard_48.png",


        "64": "images/clipboard_48.png",


        "128": "images/clipboard_128.png"


    },

    "permissions": ["storage", "clipboardRead","clipboardWrite"],
    "action":{

        "default_popup":"popup.html"

    },
    "content_scripts": [
        {
          "matches": ["<all_urls>"],  // 匹配所有url
          "js": ["content.js"]
        }
      ]
}

content.js

document.addEventListener('copy', async function () {
    const res = await navigator.clipboard.readText()
    chrome.storage.local.get(["clipfilter"]).then((result) => {
        const cpLists = result.clipfilter
        if (result.clipfilter) {
            const filterRes = handlejuejin(res);
            navigator.clipboard.writeText(filterRes)
        } else {
            navigator.clipboard.writeText(res)
        }
    });
})
function handlejuejin(str) {
    if (str.includes('稀土掘金')) {
        return str.replace(/作者:.*/, "").replace(/链接:.*/, '').replace(/来源:稀土掘金/, '').replace(/著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。/, '')
    }
    return str
}



重新加载插件

image.png

可以看到当勾选了修改掘金剪切板时,我们从掘金复制的内容就不带【作者】一些相关文字了

如何调试content.js,就是直接打开开发者工具的控制台就可以了

坑:当开发content.js时,已经重新加载了插件,但是还是不生效,提供以下思路:1.修改manifest.json的version ; 2. 刷新浏览器页面

其他知识

上述的开发,主要应用了actioncontent_scripts,常用的还有background

  • action是一个浏览器操作API,可以让你控制浏览器工具栏上的插件图标的行为和外观,例如显示或隐藏、改变颜色、添加徽章等。action API相比于browserAction和pageAction API,有更简洁和灵活的设计,可以让你根据不同的上下文来调整插件图标。在Manifest V3中,你需要使用action字段来指定你的图标信息,而不是browser_action或page_action字段。
  • content_script是一个在已加载到浏览器的页面上下文中执行的JavaScript脚本,可以读取和修改页面的DOM内容,也可以使用一些WebExtension APIs。content_script只能访问WebExtension APIs的一个小的子集,但是它们可以使用通信系统与后台脚本进行通信,从而间接的访问WebExtension APIs。你可以在manifest.json中使用content_scripts字段来声明式地加载content_script,或者使用tabs.executeScript() API来程序式地加载content_script。
  • background是一个在后台运行的JavaScript脚本,可以访问所有WebExtension APIs,但是不能直接访问页面的内容。background脚本可以用来监听浏览器事件、管理全局状态、与其他部分进行通信等。在Manifest V3中,你需要使用service_worker字段来指定你的background脚本,而不是background字段。
发布

至于如何发布到google商店,由于google开发者需要付费,仅支持G Pay,我没有符合的卡,所以如果有相关需求,请自行搜索

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYMLFGWh' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片