开发谷歌浏览器截图插件

背景

前端经常会有一些截图/生成快照的需求。但是js并没有支持截图的api,所以网上实现快照的方式原理无外乎都是一个套路来做:

  1. 读取document中的dom节点
  2. 把dom元素画到canvas上
  3. 把canvas转为img

比较成熟的一个插件就是html2canvas,这种方式能实现很多场景的截图需求了,但还是存在几个弊端:

  1. 因为安全策略(浏览器同源策略),无法截取iframe里的内容,此时截取出来可能是黑色/白色(iframe容器大小)
  2. 跨域资源图片也无法截图,原因是出于浏览器安全策略,不允许这未经许可拉取远程网站信息而导致的用户隐私泄露
  3. 因为最终是绘制到canvas上,所以会出现截图不清晰问题

这种方式能够满足大部分的无iframe嵌套场景了,但是对于网页中使用了iframe的页面,就显得无能为力了。这时候很多就该想到怎么借助浏览器本身来帮我们做到截图功能了

浏览器自带的截图功能

其实谷歌浏览器是有自带截图功能的,用法也比较简单:

  1. 进入调试模式 f12/Command +Option +I

  2. 打开命令窗口 ctrl+shift+p/Command+Shift +P

  3. 输入指令capture,会有三个选项

    截图指令

    1. Capture area screenshot 任意区域截图(自选区域)
    2. Capture full size screenshot 截取全屏
    3. Capture node screenshot node模式
    4. Capture screenshot 截取当前范围

    用鼠标点击或者键盘选择就可以使用对应的功能了

但是这个操作成本有点大,对于外行人来说,需要经过一定的培训才会使用,这样的话就会增加培训成本,第二个的话,这个截图无法耦合到项目中,会增加操作成本,最终效果可能还不如使用譬如微信qq提供的快捷截图功能,强行安利这个的话显得很麻瓜

开发截图插件,与项目耦合

虽然谷歌商店中也有其他好用的截图插件,但是实际效果可能跟使用自带的截图功能差不多,还是无法跟项目产生联动效果。所以需要提供一个操作成本更低的功能给用户使用,这时候就可以想到,为什么我们项目中不能调用自带的截图功能呢?想法很美好,现实很残酷,因为谷歌js引擎的运行环境和谷歌插件的运行环境互相隔离的,所以我们无法通过js去调用到对应的api,所以需要自己开发一个插件来实现这样的功能。自己开发有几个优缺点:

  1. 需要额外的安装插件,用户的学习成本和技术支持的额外支出(比较明显的一个缺点)
  2. 技术的学习成本
  3. 可拓展性强,可以在此基础上拓展其他功能,是一条可持续发展道路
  4. 可维护性强,因为插件是一个独立的项目

权衡下来,可以自己动手做一下。

需要了解的基本信息

谷歌浏览器插件开发文档(不然经常打不开)

因为是外网,所以可能出现无法访问的情况,无法访问的同学也可以使用360浏览器的插件开发指南地址来,因为用的内核是一样的,所以大部分api还是一致的

创建manifest.json,这是插件的元数据,插件的配置信息,任何插件都必须要有这个文件,任何插件都必须要有这个文件

{

"manifest_version": 2,

"name": "插件名",

"version": "1.0", // 用来判断是否需要更新

"description": "插件描述",

"browser_action": {

"default_icon": "static/favicon.ico", // 插件图标

"default_title": "插件图标上显示的内容",

"default_popup": "pages/popup.html"

},

"background": { // 后台运行的js,相当于后台进程

"scripts": ["scripts/background.js"],

"persistent": false

},

"permissions": [ // 授权信息 - 那些网站或者其他tab的授权

"tabs",

"unlimitedStorage",

"notifications",

"history",

"activeTab",

"storage",

"webRequestBlocking",

"*://*/*",

"http://*/*",

"https://*/*"

],

"web_accessible_resources": [ // 注入到网页的内容

"scripts/inject.js"

],

"content_scripts": [{ // 内容js

"matches": ["http://*/*","https://*/*", "*://*/*"], // 匹配那些网站

"js": ["scripts/jquery.min.js", "scripts/inject.js"],

"run_at": "document_start"

}]

}

项目结构

    ├── scripts                         脚本内容

│ ├── background.js

│ ├── index.js

│ ├── inject.js

│ ├── jquery.min.js

│ ├── popup.js

├── pages 页面内容(弹出页,背景页)

├── static 静态资源文件

├── styles 样式

├── manifest.json chrome插件配置

├── README.md 项目描述文件

代码示例

popup.html 点击图标显示的内容, 在browser_action.default_popup 设置

<body>

<ul>

<liclass="CaptureScreen">网页截图</li>

</ul>

</body>

<scriptsrc="../scripts/index.js"></script>

scripts/index.js 入口页

const $CaptureScreenBtn = $('.CaptureScreen') // 截屏按钮

const popup = {

// 初始化

_init () {

this._initialEvent()

this._initScript()

},

// 事件初始化

_initialEvent () {

$CaptureScreenBtn.click(this.handleCaptureScreen)

},

// 脚本初始化

_initScript () {

this._sendMsg({ action: 'INJECT_SCRIPT' })

},

// 发送消息,和html通讯

_sendMsg (message, callback) {

// 对runtime发送消息

chrome.runtime.sendMessage(JSON.stringify(message), function(response) {

if (callback) callback(response)

})

},

// 接收消息

_getMsg () {

// 监听runtime中的信息

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {

switch (request.action) {

default:

break

}

})

},

// 开始截屏

handleCaptureScreen () {

// 获取当前窗口 -> 回调函数包括当前窗口的详细信息,如窗口id等

chrome.windows.getCurrent(function (win) {

// 抓取当前tab的内容

chrome.tabs.captureVisibleTab(win.id, {}, function (dataUrl) {

const info = {

action: 'CAPTURE_SCREEN',

payload: dataUrl

}

popup._sendMsg(info)

})

})

}

}

scripts/background.js

  • 后台进程,用于监听消息和转发消息
  • 可以操作html

// 消息群集

chrome.runtime.onMessage.addListener(onRuntimeMessage)

functionsendPostMsg (info) {

window.postMessage(JSON.stringify(info), '*')

}

// 监听runtime消息

/**

* @param {*} request

* @param {*} sender

* @param {*} sendResponse

*/

functiononRuntimeMessage (request, _, sendResponse) {

// Tips: 需要sendResponse,不然可能会阻塞其他消息

const { action, payload } = JSON.parse(request)

sendResponse()

}

// 向网页注入js代码

functioninjectScript () {

const link = 'scripts/inject.js'

const temp = document.createElement('script')

temp.setAttribute('type', 'text/javascript')

// 获得的地址类似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js

temp.src = chrome.extension.getURL(link)

temp.onload = function() {

// 放在页面不好看,执行完后移除掉

this.parentNode.removeChild(this)

}

document.head.appendChild(temp)

}

scripts/inject.js 此代码会注入到网页,所以在这边做为插件和网页的桥梁,通过postmessage来交互

// 监听消息

window.addEventListener('message', receivedMessage, false)

// 发送postmessage消息

functionsendPostMsg (info) {

window.postMessage(JSON.stringify(info), '*')

}

调试

不管是撸代码的时候还是写完逻辑的时候,我们都期望能根据实际的表现来做出对应的操作,所以就涉及到调试了。Chrome直接支持javascript的调试,拥有了Chrome,就相当于拥有了一个强大的javascript调试器了。

调试Content Script

打开开发者工具,点击sources,找到对应的文件-> scripts/index.js,点击打开,就可以和平时调试js一样调试了

调试Background

由于background和content script并不在同一个运行环境中,因此上面的方法是看不到Background的javascript的。要调试Background,还需要打开插件页,也就是“chrome://extensions”。点对应的插件的“generated background page.html”,就出现了调试窗口,接下来的操作就跟前面的类似了。

调试Popup

虽然Popup和Background是处于同一运行环境中,但在刚才的Background的调试窗口中是看不到Popup的代码的。所以需要审核弹出内容,然后就跟之前的调试操作差不多了

调试inject

inject的话就会把代码注入到网页中,和conten相似的方式即可

总结

因为之前没有相关的开发经验,所以开始的时候会有点慌张,其实发现只要放平心态,认真仔细的阅读开发文档,入门还是不难的。通过这次的实践,我差不多已经知道怎么去开发一款chrome插件了,当然,chrom插件的功能是非常强大的,这次用到的仅是冰山一角,要深入,还需要更加充分阅读文档和实践了。

以上是 开发谷歌浏览器截图插件 的全部内容, 来源链接: utcz.com/a/33469.html

回到顶部