背景
某天晚上浏览掘金时无意发现 炸掘金 的创意游戏,虎躯一震,想到自己以前很想做一个将页面元素分离的特效,但因为工作忙(lan)没有实践起来,现在因为疫情居家办公,时间比以前多了 可以大胆摸鱼,为啥不趁这个机会实现一下呢?
查阅文档
那咱撸起袖子就是干,大致想法是通过 chrome 插件实现页面元素脱落的效果,所以先查阅 谷歌插件开发文档 (需要梯子),逐渐厘清了几个要点
首先是 manifest 文件
每个插件都需要有 manifest.json 文件,提供关于插件的一些重要信息
其中必填的字段:
字段名 | 解释 |
---|---|
manifest_version | 描述 manifest 文件的版本 |
name | 插件名称 |
version | 插件的版本 |
推荐填写的字段:
字段名 | 解释 |
---|---|
description | 插件简介 |
icons | 插件图标 |
action | 使用 chrome.action API 控制浏览器工具栏中插件图标的行为 |
其它看起来比较厉害的字段:
字段名 | 解释 |
---|---|
background | 注册 service_worker 的地方 |
commands | 给插件添加快捷键指令 |
content_scripts | 在当前网页环境中运行的文件 |
permissions | 声明在运行时需要的插件权限 |
其次是插件提供的能力
写插件前咱得知道插件能提供啥炫酷功能嘛不是,开发文档里有两个 nice 的归纳总结:
然后根据自己想实现的功能开整
编写逻辑
咱是想点击工具栏的插件图标后,页面元素开始往下掉落,所以需要查查 API 文档,看怎么监听插件图标的点击事件并操作页面内容
很快啊,我的目光聚焦在这两个 API 上:
chrome.action.onClicked
点击插件图标chrome.scripting
在不同页面中执行脚本
现在万事俱备,只差代码了,咱先组织下 manifest.json
文件,汇总下插件的信息:
// 这里只列出运行逻辑相关的字段哈
"background": { // 还记得之前在表格里介绍的 background 字段吗 嘿嘿
"service_worker": "background.js" // 文件路径为插件根目录下哦
},
"permissions": ["activeTab", "scripting"] // 调用 chrome API 中需要声明的权限信息
是滴,对于这个插件而言,最关键就上面这两个字段
让我们 look look background.js
里写的是啥:
// 监听插件图标的点击事件
chrome.action.onClicked.addListener(tab => {
// 在当前页面执行 script.js
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['script.js']
})
})
接下来非常丝滑地过渡到 script.js
,这里是实现页面元素掉落的逻辑:
/**
大致思路为:
1. 遍历页面元素,添加特定 class
2. 在 head 插入特定 class 的样式声明,让页面按照预期动起来
3. 动画结束后移除 head 的特定 class 声明
*/
// 寻找最底层节点并执行特定逻辑
function visit(node) {
if (node.children.length) {
for (const el of node.children) {
visit(el)
}
} else {
// 执行逻辑,如添加特定 class 等
node.classList.add('drop-off-extension')
}
}
// 添加特定样式声明
function addDropOffStyle() {
const style = document.createElement('style')
// 添加特定 class 的具体样式声明
style.innerHtml = '.drop-off-extension {transform-origin: top left; animation: hinge 2s; @keyframes hinge { 0% {animation-timing-function: ease-in-out;} 20%,60% {transform: rotate3d(0, 0, 1, 80deg);animation-timing-function: ease-in-out;} 40%,80% {transform: rotate3d(0, 0, 1, 60deg);animation-timing-function: ease-in-out;opacity: 1;} 100% {transform: translate3d(0, 700px, 0);opacity: 0;}}}'
document.head.appendChild(style)
// 动画执行结束后移除特定 class 样式声明
setTimeout(() => {
document.head.removeChild(style)
}, 6000)
}
visit(document.body) // 从 body 开始遍历
addDropOffStyle()
最后就是不断地调试和优化效果了 :)
最终效果展示
完美~