最近在参加一个up主/博主(不晓得怎么描述哈哈)举办的的mini黑客马拉松(群友自发玩票,图个开心) ,具体是谁就不透露了,免得有打广告的嫌疑
tips:黑客马拉松概念源自美国,一群高手云集一堂,几十个小时里开发出一款作品,累了或坐或卧,现场休息,做完当场交作品,是"世界上最酷的开发者狂欢"。
当然受困于技术水平(不是高手,上限和下限都很突出)和组织形式(群友自发玩票),没法做到几十个小时不眠不休开发一个作品,所以时间、作品形式都是无限制的;没有过多考虑就选择了用浏览器插件做一个每日情话的消息提示notifications,原因是:
- 一我是从事前端开发的,ChromeExtension除开一些特殊的API与限制,其他的完全可以基于前端三件套html、css、JavaScript来开发,所以前端福音jQuery、angular、react、vue也是可以使用的;
- 二是因为白天要做本职工作,精力、能力有限,做不了高精尖的产品,插件在不发布到商店的前提下还是蛮方便的,直接拖进浏览器就行,不用部署,就挺好。
这里使用了MV3版本来创建,因为chrome商店将在2022年6月停止接受新的MV2扩展上传,在2023年1月过后停止接受已有的MV2扩展更新,并且停止运行MV2扩展,所以文中也会提到一些2和3的不同
一、首先是创建插件的入口文件manifest.json
它包含了插件的名称、版本等信息,
{
"manifest_version": 3, //2或3,告诉浏览器你是使用哪个版本
"name": "hackathon", //插件/扩展的名称
"version": "1.0.0", //插件的版本
/*前三项是必须有的*/
"action": { "default_popup": "popup.html" },
"permissions": [
// 需要用到的权限
"notifications"
],
"background": {
"service_worker": "background.js"
}
}
如果你希望使用MV2版本来创建,则需要把清单文件中的"manifest_version": 3
改为2,"action"
改为"browser_action"
,"background"
中"service_worker"
改为"scripts"
或者"page"
,MV2中background.js会自动生成一个html的背景页,MV3为了提升性能将后台脚本放在了service works环境中,因此不会常驻后台,而且也没有后台页面了,所以也无法操作DOM相关了
{
"manifest_version": 2,
"browser_action": {},
"background": {
"scripts": ["background.js"]
// "page": "background.html"
}
}
二、然后创建插件的图标弹窗页面popup.html和popup.js
这里有些方法可能会重复使用,就做了简单的封装,放在utils中,API使用了故梦:https://api.gmit.vip/Docs#/Doc/go的随机一言,这个是免费的感谢故梦大佬
// utils
const $ = selector => document.querySelector(selector)
async function request() {
const req = await fetch('https://api.gmit.vip/Api/YiYan?format=json')
const res = await req.json()
const { text } = res.data
const options = {
title: '每日情话',
message: text,
type: 'basic',
iconUrl: '/assets/logo.png',
buttons: [{title: '毁灭吧'}, {title: '再来一个'}]
}
return options
}
// popup.js
const btn = $('#btn')
btn.onclick = async () => {
const options = await request()
chrome.notifications.create('random', options, () => console.log('桌面通知已就绪'))
}
<body>
<button id="btn">每日情话</button>
<script src="utils.js"></script>
<script src="popup.js"></script>
</body>
主要是用了插件的notifications
API,他的create方法接受三个参数(id,options,callback)
其中options可选项有
参数 | 描述 |
---|---|
type | 类型,必须指定,“basic”, “image”, “list”, “progress” |
iconUrl | 图标,必须指定 |
title | 标题,必须指定 |
message | 通知主要内容,必须指定 |
contextMessage | 通知附加内容,以较小字体显示 |
buttons | 会如下图所示出现最多两个按钮 |
此时点击popup页面中的按钮就会是这个效果:
有按钮就会有点击事件,有点击事件就会有返回值,那么系统通知的点击事件插件如何获取到呢,不急,咱们放在background.js里讲
三、创建background.js
消息提示的按钮点击事件通过notifications
API的onButtonClicked.addListener获取,该方法会传入一个回调函数,函数的参数可以获取到消息通知的id和点击的button的下标,因为最多两个按钮所以下标的值是0或1
chrome.notifications.onButtonClicked.addListener(async (notificationId, buttonIndex) => {
console.log('click',notificationId, buttonIndex)
if (buttonIndex === 1) {
const options = await request()
chrome.notifications.update(notificationId, options, (wasUpdated) => console.log('update', notificationId, wasUpdated))
}
})
MV3此时是会报错的,因为request封装在了utils.js里,如果是MV2我们可以通过在背景页直接引入utils.js或者在manifest.json
里通过background
的scripts
引入来解决,但是MV3没有背景页而且也没有scripts
如何获取到外部js呢?MV3可以在manifest.json
里通过background
的"type": "module"
开启权限,就可以在background.js中使用import导入外部的方法,或者通过在background.js中使用importScripts(‘xx.js’, ‘yy.js’)语句引入外部方法
此处我们使用第二种方法,因为引入可能会因为路径原因出错,js是至上而下执行,遇到错误就不往后执行了,所以我们用try/catch将其包裹起来,当我们点击下标为1的按钮,我们再次请求随机一言的接口,通过notifications
的update方法更新消息提示,该方法可以传入三个参数(id,options,callback),与创建的create方法类似,甚至回调函数还可以接收到布尔值
try {
importScripts('utils.js')
}catch (e) {
console.log(e)
}
chrome.notifications.onButtonClicked.addListener(async (notificationId, buttonIndex) => {
console.log('click',notificationId, buttonIndex)
if (buttonIndex === 1) {
const options = await request()
chrome.notifications.update(notificationId, options, (wasUpdated) => console.log('update', notificationId, wasUpdated))
}
})
至此一个简单的消息通知demo就完成啦!当然这还很初级,还有很多玩法,比如可以在插件栏对图标做文章(vue和react的devtools插件在是对应语法开发的网页图标会亮起,平时灰色状态,看了下代码,vue的插件是通过切换亮色和灰色的图片来实现的,react的没有深究过不知道是不是一样的,知道的小伙伴可以在评论区评论下)
// mv2
chrome.browserAction.setIcon({path: ''}) // 设置展示的图标
chrome.browserAction.setTitle() // 设置鼠标划过的提示文字
chrome.browserAction.setBadgeText({text: ''}) // 设置图标下方badge的文字
chrome.browserAction.setBadgeBackgroundColor({color: ''}) // 设置图标下方badge的背景色
// mv3
chrome.action.setIcon({path: ''}) // 设置展示的图标
chrome.action.setTitle({title: ''}) // 设置鼠标划过的提示文字
chrome.action.setBadgeText({text: ''}) // 设置图标下方badge的文字
chrome.action.setBadgeBackgroundColor({color: ''}) // 设置图标下方badge的背景色