背景
前端经常会有一些截图/生成快照的需求。但是js并没有支持截图的api,所以网上实现快照的方式原理无外乎都是一个套路来做:
- 读取document中的dom节点
- 把dom元素画到canvas上
- 把canvas转为img
比较成熟的一个插件就是html2canvas,这种方式能实现很多场景的截图需求了,但还是存在几个弊端:
- 因为安全策略(浏览器同源策略),无法截取iframe里的内容,此时截取出来可能是黑色/白色(iframe容器大小)
- 跨域资源图片也无法截图,原因是出于浏览器安全策略,不允许这未经许可拉取远程网站信息而导致的用户隐私泄露
- 因为最终是绘制到canvas上,所以会出现截图不清晰问题
这种方式能够满足大部分的无iframe嵌套场景了,但是对于网页中使用了iframe的页面,就显得无能为力了。这时候很多就该想到怎么借助浏览器本身来帮我们做到截图功能了
浏览器自带的截图功能
其实谷歌浏览器是有自带截图功能的,用法也比较简单:
-
进入调试模式 f12/Command +Option +I
-
打开命令窗口 ctrl+shift+p/Command+Shift +P
-
输入指令capture,会有三个选项
- Capture area screenshot 任意区域截图(自选区域)
- Capture full size screenshot 截取全屏
- Capture node screenshot node模式
- Capture screenshot 截取当前范围
用鼠标点击或者键盘选择就可以使用对应的功能了
但是这个操作成本有点大,对于外行人来说,需要经过一定的培训才会使用,这样的话就会增加培训成本,第二个的话,这个截图无法耦合到项目中,会增加操作成本,最终效果可能还不如使用譬如微信qq提供的快捷截图功能,强行安利这个的话显得很麻瓜
开发截图插件,与项目耦合
虽然谷歌商店中也有其他好用的截图插件,但是实际效果可能跟使用自带的截图功能差不多,还是无法跟项目产生联动效果。所以需要提供一个操作成本更低的功能给用户使用,这时候就可以想到,为什么我们项目中不能调用自带的截图功能呢?想法很美好,现实很残酷,因为谷歌js引擎的运行环境和谷歌插件的运行环境互相隔离的,所以我们无法通过js去调用到对应的api,所以需要自己开发一个插件来实现这样的功能。自己开发有几个优缺点:
- 需要额外的安装插件,用户的学习成本和技术支持的额外支出(比较明显的一个缺点)
- 技术的学习成本
- 可拓展性强,可以在此基础上拓展其他功能,是一条可持续发展道路
- 可维护性强,因为插件是一个独立的项目
权衡下来,可以自己动手做一下。
需要了解的基本信息
谷歌浏览器插件开发文档(不然经常打不开)
因为是外网,所以可能出现无法访问的情况,无法访问的同学也可以使用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>
<li class="CaptureScreen">网页截图</li>
</ul>
</body>
<script src="../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)
function sendPostMsg (info) {
window.postMessage(JSON.stringify(info), '*')
}
// 监听runtime消息
/**
* @param {*} request
* @param {*} sender
* @param {*} sendResponse
*/
function onRuntimeMessage (request, _, sendResponse) {
// Tips: 需要sendResponse,不然可能会阻塞其他消息
const { action, payload } = JSON.parse(request)
sendResponse()
}
// 向网页注入js代码
function injectScript () {
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消息
function sendPostMsg (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插件的功能是非常强大的,这次用到的仅是冰山一角,要深入,还需要更加充分阅读文档和实践了。
本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!代办报建
本公司承接江浙沪报建代办施工许可证。
联系人:张经理,18321657689(微信同号)。
12条评论
视死如归的架势啊!https://sdceda.com/shi/106192256/
这么经典的话只有楼主能想到!http://nhuu.yntvexp.net/test/226859314.html
楼主很有经验啊!http://www.dnf70.com/2571.html
楼主说的我也略懂!http://gc98.guchengcn.com
读了楼主的帖子,顿时马桶就通了。。。http://7i5szw.dyxsmj.net
楼主今年多大了?http://eh0.weidang1688.com
这么好的帖子,应该加精华!http://m395.zhongshenghaitian.com
大神就是大神,这么经典!http://www.guangcexing.net/voddetail/MKfHJSNj.html
祖国尚未统一,我却天天灌水,好内疚!http://wfm4.luchijie.net
视死如归的架势啊!http://www.guangcexing.net/voddetail/ekBGPbDE.html
被楼主的逻辑打败了!https://www.skypeis.com/
坚持回帖!https://www.telegramdown.org
发表评论