接上一篇文章 chrome插件开发-自动化脚本(3)
导入导出脚本
使用sheet.js js-xlsx库
可以很方便的实现导入导出功能.
- 导出功能
为了方便不同人员录制的脚本可以分享实现了这一功能,也是为了之后的批量导入脚本.导出的文件格式如下:
可以在脚本中设置多个自定义字段,为了方便使用并不和固定字段冲突,尽量用中文命名.
自定义字段
只能在set-input-value
事件中设置, 设置的方法为设置字段key
exportScript () {
// 创建一个工作薄
let workBook = XLSX.utils.book_new()
// 一个脚本一个sheet 方便之后批量导入运行
this.caseList.forEach(item => {
// 创建sheet对象
let sheetData = []
let headers = JSON.parse(JSON.stringify(fixedHeader))
// 抽出 eventList 输入事件中定义字段名称的列
item.eventList
.filter(event => event.type === 'set-input-value' && event.key && !headers.includes(event.key))
.forEach(event => {
item[event.key] = event.value
headers.unshift(event.key)
})
let caseRow = {
...item,
eventList: JSON.stringify(item.eventList)
}
if (Array.isArray(item.responseConfig)) {
caseRow.responseConfig = JSON.stringify(item.responseConfig)
}
sheetData.push(caseRow)
let sheet = XLSX.utils.json_to_sheet(sheetData, {header: headers})
// 在工作簿中添加sheet页
XLSX.utils.book_append_sheet(workBook, sheet, item.name)
})
// 转化格式,导出文件
// 创建工作薄blob
const workbookBlob = workbook2blob(workBook)
// 导出工作薄
openDownloadDialog(workbookBlob, '自动化脚本.xlsx')
}
复制代码
- 导入功能
有些场景可能需要重复执行脚本, 没有批量导入的话,需要每次去修改自定义字段
,如果设置了很多的话改起来会很麻烦. 我们可以在xlsx文件中先编辑好再直接导入进去,像这样
导入后的devtool:
解析xlsx的代码
importScript (file) {
readWorkbookFromLocalFile(file, wb => {
/**
* workBook => caseList:[]
* 1. 先把sheets循环,知道有几个脚本
* 2. 再把每个sheet中有几行循环, 知道每个脚本有几个用例
* 3. 再整合成一个大的caseList
*/
let caseList = []
wb.SheetNames.forEach(sheetName => {
let xlsxData = XLSX.utils.sheet_to_json(wb.Sheets[sheetName])
let allKeyList = getHeaderKeyList(wb.Sheets[sheetName])
let customKeyList = allKeyList.filter(key => !fixedHeader.includes(key))
let baseCaseDetail = {}
let baseEventList = []
xlsxData.forEach((data, index)=> {
// 表格里可以只保留第一行的脚本数据 其他行配置变量 节省空间
if (index === 0) {
baseCaseDetail = {
name: data.name,
urlPath: data.urlPath,
width: data.width,
height: data.height
}
if (data.responseConfig && data.responseConfig.length > 5) {
baseCaseDetail.responseConfig = JSON.parse(data.responseConfig)
}
try {
baseEventList = JSON.parse(data.eventList) || []
} catch (e) {
console.error('解析eventList失败', e)
}
}
// 处理eventList 把变量塞进去
let eventList = []
baseEventList.forEach(event => {
if (event.type === 'set-input-value' && customKeyList.includes(event.key)) {
event.value = data[event.key]
}
eventList.push(event)
})
caseList.push({
...baseCaseDetail,
name: baseCaseDetail.name + '-' + index,
eventList: JSON.parse(JSON.stringify(eventList))
})
})
})
this.$store.commit('setCaseList', caseList)
this.importFlag = true
})
return false
}
复制代码
单个脚本-不同变量多次运行
使用场景: 各个网站表单自动输入提交, 上面的导入功能已包含这个功能
公司网站 传参调用 第三方网站的脚本
本次优化最大的功能就是这个了, 可以有很多想象的空间, 由于我们公司是做人力资源外包的, 办理人员一直需要在政府社保网站
操作人员的入职,转入,封存,启封 这种频繁的操作. 所以想做这个功能节省人员的工作量,并且提高效率.
第一步 配置manifest.json
externally_connectable
字段定义可以直接使用 chrome.*
api的站点,通配符配置有一些是不支持的,所以域名需要精确一点.
"externally_connectable": {
"matches": ["http://localhost:63342/*"]
}
复制代码
第二步 网页中通知第三方网站执行哪个脚本
这里我们要知道用什么方式通知第三方网站, 首先第三方网站需要打开devtool
工具我们才能执行脚本.
然后就可以在配置页面使用 chrome.* api 发消息给 background.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>本地测试页面</title>
</head>
<body>
<div>
<span>tabId</span> <input id="tabId" value="759"/>
</div>
<div>
<span>脚本名称</span> <input id="name" value="掘金搜索"/>
</div>
<div>
<span>搜索关键字</span> <input id="key" value="哈哈"/>
</div>
<button id="button-1">调用其他页面脚本</button>
<div>
<span>执行结果</span> <pre id="response"></pre>
</div>
<script src="https://juejin.cn/post/autoScript/js/jquery-1.8.3.js"></script>
<script>
$('#button-1').on('click', sendMessage)
function sendMessage () {
let editorExtensionId = 'odfckenjjgjokihccfabfoecjclggmka'
let tabId = $('#tabId')[0].value
let name = $('#name')[0].value
let key = $('#key')[0].value
chrome.runtime.sendMessage(
editorExtensionId,
{tabId: tabId, data: {type: 'run-case', name: name, customKey: {'搜索关键字': key}}},
(response) => {
$('#response').text(JSON.stringify(response, null, 2))
console.log(response.success)
}
)
}
</script>
</body>
</html>
复制代码
第三步 background.js 分发请求
这部分相对简单, 不使用长连接postMessage因为不能回调,不能很方便的通知到原网页请求的结果.
// 监听externally_connectable配置的正常网页发送的消息
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
if (request.tabId in connections) {
// 不使用长连接发送消息 原因是不能设置回调
// connections[request.tabId].postMessage(request.data)
chrome.runtime.sendMessage(request, response => {
sendResponse(response)
})
return true // 返回 true 表示是异步回调
} else {
sendResponse({error: 'onMessageExternal Tab not found in connection list.'})
}
})
复制代码
第四步 第三方网页的 devtool 监听消息 执行并返回
Main.vue
/**
* 长连接没有sendResponse回调, 所以使用这种方式回调
*/
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
let message = msg.data
console.log('devtool chrome.runtime.onMessage', msg)
if (+msg.tabId === +chrome.devtools.inspectedWindow.tabId && message) {
switch (message.type) {
case 'run-case':
// 1. 找到脚本 并替换变量
// 2. 执行脚本
let index = this.caseList.findIndex(item => item.name === message.name)
if (index < 0) {return}
let newCase = JSON.parse(JSON.stringify(this.caseList[index]))
newCase.eventList = newCase.eventList.map(event => {
if (event.type === 'set-input-value' && event.key in message.customKey) {
event.value = message.customKey[event.key]
}
return event
})
Vue.set(this.caseList, index, newCase)
this.$EventBus.$emit('run-case', {index, sendResponse}) // 发送给真正执行的页面
return true
}
}
})
复制代码
home.vue
this.$EventBus.$on('run-case', async ({index, sendResponse}) => {
await this.runCase(index)
sendResponse(this.result[this.caseList[index].name])
})
复制代码
到此为止, 我们就可以在自己做的页面上调用其他网页上已经录制过的脚本了.
完整演示
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END