使用Vite+Vue3开发谷歌浏览器插件【V3版本】
使用vite+vue3开发谷歌浏览器插件,本文针对已对浏览器插件有了解的对象,对浏览器插件的介绍不做赘述,本文不完全是开发教程,更多的为本人日常学习记录,用来记录项目中相对重要以及需要注意的点,以实操和实现功能为主,如有疑问可联系博主解答相关问题。
本文针对已对浏览器插件有了解的对象,对浏览器插件的介绍不做赘述,本文不完全是开发教程,更多的为本人日常学习记录,用来记录项目中相对重要以及需要注意的点,以实操和实现功能为主,如有疑问可联系博主解答相关问题。
背景介绍:做一款可以在vx公众号后台编辑页插入文字/图片的插件,本文围绕以下几点来做说明:
- 因为插入文字/图片到vx公众号需要借助vx本身的编辑器,vx把UE编辑器对象挂载到了window中,因此需要借助挂载到window中的UE对象来进行插入操作
- 因为我们的项目中用到了Vite+Vue3,因此如果想获取vx的window对象只能通过注入js来完成,在.Vue文件中是获取不到vx的window对象的
- 借助options页来做登录
- 借助options传递给background消息做登录跳转到目标页
manifest.json
"name": "xxx",
"version": "1.0",
"description": "xxx",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["*://mp.weixin.qq.com/cgi-bin/appmsg*"], // 只针对此链接生效
"css": ["content.css"],
"js": ["content.js", "js/jquery-1.12.4.min.js", "js/crypto-js.min.js"],
"run_at": "document_end"
}
],
"options_ui": {
"page": "options.html",
"open_in_tab": true // 安装插件时,默认打开options.html
},
"permissions": ["storage", "declarativeContent", "tabs"], // 使用到的权限
"host_permissions":[],
"web_accessible_resources": [
{
"resources": [ "/images/icon16.png" ],
"matches": ["<all_urls>"]
},
{
"resources": [ "insert.js" ], // 注入的js,用来做ue编辑器的通信
"matches": ["<all_urls>"]
}
],
"action": {
"default_popup": "index.html",
"default_icon": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
"default_title": "xxx"
},
"icons": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
首先从options登录开始
我选择了在options中做登录,是因为谷歌API提供了非常好的一个操作,那就是用户第一次安装插件的时候会自动打开options页,在options做登录是个不错的选择
我的options页长这样:
现在我们需要考虑的是,登录完成之后如何保存用户信息、跳转到vx后台编辑页、监听存储的用户信息
使用storage保存用户信息,这是谷歌提供的API方法:
chrome.storage.sync.set({'myKey': JSON.stringify(data.data)}, function() {
console.log("The myKey.");
});
拿到用户信息之后,我们需要跳转到目标页面,假设目标页面是a,那么我们需要在已打开的窗口用查到a这个标签页进行跳转,首先在options.js是中是不具备这个能力的,那么我们就需要和background.js进行通信,借助background.js来做中转消息,background不做介绍,我们可以把它理解成中转站即可。
在options.js发送消息
chrome.runtime.sendMessage({ action: 'returnToPageACloseOptions' });
background接收options消息
在background.js中进行接收,跳转、关闭options、刷新页面具体看代码注释
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
// 接收来自content options insert的消息,request里不允许传递function和file类型的参数
chrome.tabs.query({currentWindow: true}, function (tabs) {
const { contentRequest, action } = request
// 接收到options登录页成功登录信息
if (action ==='returnToPageACloseOptions') {
let mpWeiXin = []
for (var i = 0; i < tabs.length; i++) {
console.log('Tab ' + i + ': ' + tabs[i].url); // 获取到已打开的所有标签页
if (tabs[i].title === 'a') {
mpWeiXin.push(tabs[i].id)
chrome.tabs.update(tabs[i].id, {active: true}); // 跳转到目标页a
chrome.tabs.remove(sender.tab.id); // 关闭options登录页
// 跳转到目标页后刷新页面加载,在background中通知content_script加载
chrome.tabs.reload(tabs[i].id); // 跳转到a页面后进行刷新执行content.js逻辑
}
}
// 判断浏览器是否打开了包含“a”的页面
if (mpWeiXin.length === 0) {
// 关闭options页
chrome.tabs.remove(sender.tab.id);
window.open('a')
return false
}
}
})
return true
})
content.js
跳转到a目标页刷新后,这时候我们在content.js写的逻辑才算真正开始执行,我们在content写了监听storage方法,在options登录成功后我们执行过storage方法,一旦storage有变化,那么我们都可以监测到执行相应的业务逻辑
content.js 两个作用:
- 用来监听storage,控制插入到页面的元素显示隐藏
- 注入insert.js,注入insert.js的目的是它相当于一个外部js,content是一个内部js,为什么这样说?是因为此项目是用vue来做的content.js可以和vue相结合来执行一些操作,可以理解为就像我们在main.js引入了这个js,而insert.js是独立开的,看到这有的同学就会明白了,在insert.js中我们可以获取vx的window对象!
chrome.storage.onChanged.addListener(function (result) {
if (result.myKey) {
// chrome.storage.onChanged获取到有newValue和oldValue包裹
const getMyKey = result.myKey && result.myKey.newValue
if (getMyKey) {
const myKey = (JSON.parse(getMyKey))
localStorage.setItem('myKey', JSON.stringify(getMyKey)) // 本地存储一份
$('.tab').css('display', 'block') // 注入到a页面的html展示
window.postMessage({"login": true, userInfo: myKey}, '*'); // 发送消息给a.vue
}
} else {
$('.tab-box').css('display', ' none')
localStorage.removeItem('myKey')
}
})
在a.vue中我们全局监听message根据传递的消息执行对应的业务逻辑
onMounted(()=>{
window.addEventListener('message', (e)=>{
if (e.data.login) {
......
}
})
})
当我们在a.vue点击文字或者图片时,我们需要传递消息给insert.js
const setContent = (v) => {
console.log('setContent')
window.postMessage({type: 'insert', content: v}, '*')
}
insert.js
- 在insert.js中获取ue对象
- 在insert.js中执行和ue相关的操作
window.onload = function () {
var ue = window.parent.UE && window.parent.UE.getEditor('js_editor');
window.addEventListener('message',(e)=>{
let { type, content, highlightedText } = event.data;
if (type === 'insert') {
ue.execCommand('insertHtml', `<img src="${content}">`)
}
})
}
像options和background中消息的传递我们可以使用官方API进行,但往往有些时候我们需要自定义文件,而自定义的文件并不能使用官方提供的API,我们就需要借助window.postMessage来进行消息的传递
以上是我个人的学习记录,希望能帮到大家,如有疑问可向我咨询,共同学习。
AIGC爱好者 专注前端开发AI提效 欢迎大家进行交流 共同学习
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)