当前位置:网站首页>第105期:一次失败的浏览器插件开发
第105期:一次失败的浏览器插件开发
2022-07-15 12:35:00 【terrence386】
这周没有频繁的更新文章。一方面是时间的原因,另一方面是自己有点懒了。
因为自己有写文章的习惯,之前写文章都是用别的平台,写好了再复制到掘金以及各个平台进行分发。但是一直存在的问题是,每次写的时候总是总是会很麻烦,所以想着自己开发一个写文章的工具,存到自己的数据库中,这样也方便以后自己做迁移。
但是,自己开发一套前端+服务端的东西,我自己写起来有比较费劲。所以想直接开发个基于掘金文章功能的浏览器插件,每次直接在掘金上写,写完了直接点开插件进行复制分发,一键上传git仓库,一键生成海报等功能,这样岂不是方便很多?
然后设计了一下大致的界面:
image.png
思考了一下想要实现的功能主要有三个:
- 一键复制富文本
- 生成海报
- 推送文章内容到指定仓库
一键复制富文本这个功能,原本想着很简单,因为原先写过一个类似的东西,找到过一些代码,可以把外部样式表转为行内样式,原本以为这个直接粘过来用就可以了,但是实际上的情况是,文本的样式可以正常复制,但是由于hljs内置的样式无法转换为行内样式,所以类似下面这种示例代码虽然可以复制,但是完全没有样式。
即便我在插件中重新定义了一套样式直接appendChild到body,复制出来示例代码部分也没有变成行内样式,复制出来的效果也不对。
转换行内样式的代码如下:
// 将样式表的样式装换成行内样式
let sheetToSelf = function (dom) {
const sheets = document.styleSheets;
const sheetsArry = Array.from(sheets);
const $dom = dom.parentNode
console.log(sheets)
function cssTextToJSON(cssText) {
const arr = cssText.split(';')
arr.splice(arr.length - 1, 1)
const obj = {}
arr.forEach(function (item) {
const attrName = item.split(':')[0]
obj[attrName.replace(/ /g, '')] = item.split(':').map(function (i, index) {
return index ? i : ''
}).join('')
})
return obj
}
let sheetsArryneed = sheetsArry.filter(item => item.type !== 'text/css')
sheetsArryneed.forEach(function (sheetContent) {
console.log('sheetContent---', sheetContent)
const {
cssRules
} = sheetContent;
//cssRules兼容火狐
const rulesArry = Array.from(rules || cssRules || []);
if (rulesArry) {
rulesArry.forEach(rule => {
const {
selectorText,
style
} = rule;
if (selectorText !== '*') {
try {
const select = $dom.querySelectorAll(selectorText);
select.forEach(function (dom) {
if (dom.style.cssText) {
const oldCssText = cssTextToJSON(dom.style.cssText);
const newCssText = cssTextToJSON(style.cssText);
for (let i in newCssText) {
oldCssText[i] = newCssText[i]
}
for (let i in oldCssText) {
dom.style[i] = oldCssText[i]
}
} else {
dom.style.cssText = style.cssText
}
})
} catch (e) {
console.log('转换成行内样式失败', e);
}
}
})
}
})
}
复制文章的代码如下:
const copy =()=> {
let article = document.querySelector('.markdown-body')
let t = document.getElementById("copy-input");
t || ((t = document.createElement("input")).id = "copy-input",
t.style.position = "absolute",
t.style.left = "-1000px",
t.style.zIndex = "-1000",
t.style.visibility = 'hidden',
document.body.appendChild(t)),
t.value = "NOTHING",
t.setSelectionRange(0, 1),
t.focus(),
document.addEventListener("copy", function t(n) {
n.preventDefault(),
n.clipboardData.setData("text/html", article.innerHTML),
n.clipboardData.setData("text/plain", article.innerHTML),
alert('已复制,请到邮箱中粘贴')
document.removeEventListener("copy", t)
}),
document.execCommand("copy")
}
但是没达到预期效果。
分享海报这个功能就不说了,因为没写。
一键上传git仓库呢。原本想的是,在界面上配置一下要推送的仓库地址,然后在起个服务,拿到配置的仓库地址和本地路径,在服务中切换到对应的目录,执行git 上传脚本,不就完事儿了?当然,上传之前需要将文章内容通过文件流API写到本地,然后用childprocess 执行上传脚本,多么完美,甚至demo我大致都写好了。
let cp = require("child_process");
// 判断
let fileDir = process.env.Home; // 系统盘目录
let platform = process.OS; // 'Windows_NT' || mac
console.log("fileDir---", fileDir);
cp.exec(
"cd C:\\Users\\terrence\\study & git log",
(error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
}
);
但是我忽略了一个重要的点,服务端是无法操作客户端的脚本的。即便我起了一个服务,将来这个服务执行的脚本也是服务器上的脚本。
当然,如果真的要这么做的话,就必须走类似持续集成的逻辑。
有别的实现方式吗?想了想,也许用webcontainer可以实现,webcontainer号称可以在浏览器端执行服务端脚本。
image.png
有一便介绍的相对详细的文章https://zhuanlan.zhihu.com/p/446329929。但是对于我这个小渣渣似乎有点太过于高深了。
然后想,要不在界面上嵌入一个客户端的bash窗口?直接执行客户端命令?
于是又找来xterm的文档看了看,界面容易嵌入,但是脚本还是需要起一个服务进行交互。所以还是行不通。
因为即便我把这个服务的代码写好了,浏览器插件也开发完成来。插件发布的时候,我也没法把服务端的代码一起发布到,也没法实现安装插件时自动在客户端启动我这个服务。
所以这个从浏览器插件一件上传到git仓库的想法有些异想天了。
但是也稍微有些收获。就是又熟悉了一下浏览器插件的开发流程,以及熟悉了如何用vite进行浏览器插件开发。
浏览器插件开发的核心在于manifest.json文件的配置。然后插件各个模块之间如何通信,我这里主要是用了popup和content进行通信,popup触发copy事件,content负责去执行真正的copy动作。
主要用的是chrome.tabs.connect()和chrome.runtime.onConnect.addListener()这两个方法。
整体来看,这次是一个失败的尝试,但是从这个两个功能的思考来看,多少还是有些收获的。
先写到这里,谢谢观看。
边栏推荐
- 【MySQL】表的内外链接
- 慢 SQL 分析与优化
- Differences and relations among RDD, dataframe and dataset in spark
- B树与B+树的区别
- Equal subtrees on binary trees
- Lesson 2 WiFi experiment of hi3861 -api-1
- Threshold psi code
- Devkit - mpc5744p configuration RTOS
- 两年前的DeFi弄潮儿,龙头、蓝筹们怎么样了?
- Analyze the meaning of "collaboration" in collaborative office, and how can digital office easily "solve the problem"?
猜你喜欢

Will the expired data of redis be deleted immediately? Great mystery

10000 words detailed SSH (SSH login principle +ssh configuration + simulated SSH secret free login)

Devkit mpc5744p configuring RTOS

TiKV & TiFlash 加速复杂业务查询

数据传输:同构异IP数据源批量抽取实践

線程-interrupt方法詳解

LNMP architecture PHP installation

Equal subtrees on binary trees

Spark中RDD、DataFrame和DataSet的区别与联系

剧说职场:资深HR告诉你职场强人都有什么特征
随机推荐
Zhihu Gaozan: Data Center -- Alibaba, Daas
Configure @ in vite to access files under Src
【MySQL】表的内外链接
Hcip notes (4)
Threshold psi code
【MySQL】多表查询
Use the kicad plug-in to visualize PCB welding
Solve the comprehensive monitoring scheme for the dynamic ring state of small and medium-sized machine rooms
MSP430 - timer (output comparison encoder speed measurement) (V)
File parsing_ Excel file parsing
慢 SQL 分析与优化
Issue 98: flutter learning (1)
【OpenCV 例程200篇】230. 特征描述之 LBP 统计直方图
基于neo4j的知识图谱构建及Py2neo的使用总结
Detailed explanation of thread interrupt method
10000 words detailed SSH (SSH login principle +ssh configuration + simulated SSH secret free login)
RobotFramework进阶(三)集成Jenkins运行自动化用例
TiKV & TiFlash 加速复杂业务查询
知乎高赞:数据中台——风起阿里,成于DaaS
ModuleNotFoundError: No module named ‘fake_ useragent‘