背景
先交代下背景,为什么会有撸个插件的想法呢,起因是公司的协议平台是h5的,首先要打开,在调试不同端项目的时候需要切换协议平台,比如58,安居客,本地版的,有时候要打开好几个页面,而且每个页面我使用的功能基本就是加个协议头,但是我还要把不用的参数一个一个删掉(如果不删的话生成的码非常复杂,不易识别),浪费很多时间,而且还要手动url,很多时候本地调试的时候想生成二维码的url就是当前页面的url,还要复制粘贴过去,再一个有时候协议平台的静态资源还报错,然后就没法用了,插件可以完美的解决我的痛点,并且可以脱机使用,所以就撸了一个插件,文章最后有插件的链接,需要的同学可以自取哈~
正文
成品图
按照国际惯例,先放成品图,功能其实很简单,一个是生成二维码(可生成带协议头的二维码),一个是解析二维码,因包含协议等敏感信息,故进行了打码处理
目录结构
看一下目录结构,是不是很眼熟,欢迎来到古老的被jquery支配的年代,哈哈开个玩笑,其实一样可以使用框架来开发,全看个人选择,因为使用jquery操作dom比较简单,功能又不是很复杂,所以这次使用了jquery
以本例着重说一下manifest和popup:
manifest:是一个插件配置文件,里面有插件的重要信息,例如插件的名称(必填),版本(必填),图标,权限,匹配路径等等,具体配置请移步谷歌插件官方文档查看(http://chrome.cenchy.com/manifest.html)
popup:是成品图中点击这个icon会弹出的页面,在里面可以写自己想要的功能,跟写html一样,是不是so easy
页面结构
接下来看一下页面结构,非常的平平无奇,主要的逻辑实现在入口js文件中
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<script src="js/jquery-1.9.1.min.js"></script>
<!-- 二维码解析库 --><script src="js/jsQR.min.js"></script>
<!-- 二维码生成库 --><script src="js/qrcode.min.js"></script>
<!-- 文本复制库 --><script src="js/clipboard.min.js"></script>
<!-- 主入口文件 --><script src="js/init.js"></script>
<body id="qr-body">
<div class="wrapper">
<header>
<h1 class="active">生成二维码</h1>
<h1>解析二维码</h1>
</header>
<div class="section-wrap create-wrap">
<div class="input-wraper">
<input id="code-url" type="text">
<div class="create-qr">生成</div>
</div>
<div class="options">
<div class="option-item">
<label for="mode"><span>模式选择:</span>协议模式</label><input class="mode" type="radio" name="mode" value="1"
checked>
<label for="mode">普通模式</label><input class="mode" type="radio" name="mode" value="2">
</div>
<div class="option-item scheme-choose">
<label for="mode"><span>协议选择:</span>58</label><input class="scheme" type="radio" name="scheme" value="58协议头"
checked>
<label for="mode">安居客</label><input class="scheme" type="radio" name="scheme" value="安居客协议头">
<label for="mode">58本地</label><input class="scheme" type="radio" name="scheme" value="58本地协议头">
</div>
</div>
<div class="qr-content">
<div id="qrcode"></div>
</div>
<div class="save-code">
<a class="download" download="qrcode.png" href="">
<p>保存图片</p>
</a>
</div>
</div>
<div class="section-wrap decode-wrap discover">
<div class="decode-result">
<p class="decode-content">解码结果:<span class="decode-str"></span></p>
</div>
<div class="input-section">
<div class="upload-tip">
<img src="img/upload.png">
<p>上传或拖拽二维码图片</p>
</div>
<input id="wait-decode-img" type="file" accept="image/jpg,image/png,image/bmp,image/jpeg"/>
</div>
<div class="copy">
一键复制
</div>
</div>
</div>
</body>
</html>
前方有怪兽出没,请注意,如不注意会发生非常可怕的事情
1.页面上的js一定要通过外链脚本的方式引入,不能写内联js,不能写内联js,不能写内联js(此处省略10086遍),否则会不生效,之前我就踩了这个坑,当时还在想是不是我哪里写的有问题
2.在页面中所有的dom操作全是基于当前popup页面的,获取不到当前导航栏地址所在的页面内容,想获取的话会有专门的api去获取,而且有限制,下面会讲到
3.
逻辑实现
看完页面结构该上正菜了,下面就是真正的逻辑实现部分了,准备面对疾风吧,比卡丘!
$(function () {
let qrcode, url, mode = $(".mode").val(),
scheme = $(".scheme").val()
const getQRStr = function () {//根据所选模式获取二维码的字符串,普通模式直接返回输入框内的字符串,协议模式要添加上协议
if (mode == 2)
return url
} else
var params = encodeURIComponent(`{"url":"${url}"}`)
return `${scheme}://xxxx/xxxx/xxxx?params=${params}`;//此处注意,实际使用中请结合协议头请拼接正确的协
const remakeStr = function () {//重新生成二维
qrcode.makeCode(getQRStr())
$(".download").attr("href", $("#qrcode img").attr("src"))//将二维码的链接赋值到保存图片按钮
const decodeQR = function (file) {//解析二维码,接收的是一个file对象,返回的是一个包含解析结果的promise对
return new Promise((resolve, reject) =>
const url = URL.createObjectURL(file),//创建一个URL对象,表示的是传入的file对
img = new Image()
img.onload = function ()
URL.revokeObjectURL(this.src);//释放之前通过URL.createObjectURL()方法创建的对
//因为解析库jsQR需要传入一个imageData对象,所以我们要把传入的file对象转成imageData对象,先通过canvas把image file绘制出来,然后通过getImageData方法拿到imageData对象
var cvs = document.createElement(\'canvas\');
var ctx = cvs.getContext(\'2d\');
cvs.width = this.width;
cvs.height = this.height;
ctx.drawImage(this, 0, 0);
//关于imageData的说明 https://developer.mozilla.org/zh-CN/docs/Web/API/ImageData
const imageData = ctx.getImageData(0, 0, cvs.width, cvs.height);//
const result = jsQR(imageData.data, imageData.width, imageData.height);
//如果result为true,说明解析成功,反之失败
resolve({
status: result ? true : false,
codeStr: result ? result.data : ""
})
};
img.src = url;
})
}
//使用clipboard可以复制传入的字符串
const clipboard = new ClipboardJS(\'.copy\', {
text: function (trigger) {
return $(".decode-str").text() || null;
}
});
//页面插件初始化的时候要拿当前页面的url填入到输入框中,最开始我使用的是location.href,但发现始终拿到的是chrome-extension://keokipipphpaaalmgnoeimafhmbjmped/popup.html,最后查阅文档才发现不能这么拿,这么拿拿到的实际是popup.html的链接,但所幸chrome官方提供了这类api,通过此api可以拿到当前tab页面的一些属性例如url(不要忘记在权限中设置)
chrome.tabs.query({
\'active\': true,
lastFocusedWindow: true,
currentWindow: true
}, function (tabs) {
url = new URL(tabs[0].url).toString();//要toString()一下,因为new URL(tabs[0].url)后拿到的不是标准的字符串,生成二维码的时候会报错,血的教训啊= =
$("#code-url").val(url);
qrcode = new QRCode("qrcode", {//初始化生成二维码
text: getQRStr(),//文本字符串
width: 196,//二维码宽度
height: 196,//二维码高度
colorDark: "#000000",//二维码线条颜色
colorLight: "#ffffff",//二维码背景色
correctLevel: QRCode.CorrectLevel.M//二维码等级,等级越高容错率越高,相应的也越复杂,当二维码所描述的文本非常长的时候,质量调的过高容易识别不出来,所以选择了M档
});
setTimeout(function () {
$(".download").attr("href", $("#qrcode img").attr("src"))
}, 1500)
});
$(".mode").change(function () {//模式改变的时候重新绘制二维码
mode = $(this).val();
if (mode == 2) {
$(".scheme-choose").addClass("discover");
} else {
$(".scheme-choose").removeClass("discover");
}
remakeStr();
})
$(".scheme").change(function () {//协议改变的时候重新绘制二维码
scheme = $(this).val();
remakeStr();
})
$(".create-qr").click(function () {//当输入框内容改变的时候只有手动点击生成才会重新生成二维码
url = $("#code-url").val();
remakeStr();
})
$("#wait-decode-img").change(async function (e) {//当上传需要解析的二维码的图片时会解析二维码
const file = e.target.files[0];
const result = await decodeQR(file);
if (result.status) {//如果status是true说明解析成功,将解析出的字符串写到页面上
$(".decode-str").text(result.codeStr);
}
});
$("#qr-body").on("click", "header h1:not(.active)", function () {//解析和生成两个tab的切换逻辑
$(".active").removeClass("active");
$(this).addClass("active");
const discoverDiv = $(".discover");
$(".section-wrap:not(.discover)").addClass("discover");
discoverDiv.removeClass("discover");
})
})
安装浏览器插件
到这里一个集识别与生成二维码的浏览器插件就诞生啦,下面讲讲如何安装浏览器插件
然后点击加载已解压的扩展程序就可以使用啦(悄悄的告诉你,直接把已解压的文件夹拖拽到页面上也可以安装),至此大功告成,需要注意的是不要移动插件文件夹所在的位置,这样会造成插件不可用,或者随便改动插件的代码,因为会立即生效,为什么会这样呢,因为我们的插件并没有发到谷歌商店上,这样会被认定为不安全的插件,只能通过类似开发者模式去使用,想要发布到商店的同学要先选择打包,会打包出crx文件和pem秘钥,然后按照商店的指示一步一步的去提交发布信息(友情提示:想要开通谷歌商店的上传资格要6美刀,且只能外币支付哦,有万事达,visa或者运通卡的小伙伴有意向的话可以自行研究,我只开通了账户,但是后续上传审核啥的有点麻烦,就放弃了)
赶赶单单吧,一点都不神秘吧,其实浏览器插件能做的有很多很多远不止今天讲的这点,比如background脚本(可以共享导航栏地址所在页面的dom,但是不能共享页面的js哈),鼠标右键的菜单,桌面通知,选项页,覆写特定页等等,今天算是给大家来一点前菜,想吃大餐的话就要靠同学们自己去做了,只要你足够有兴趣,你的浏览器你做主
最后放上链接,有需要的小伙伴自取哦,需要添加协议参数的,可以自己再二次开发,别忘了解压使用
ps:由于接触时间尚短,难免有疏漏,有错误和建议的地方欢迎指正和交流(不限于插件方面)
链接:
https://wos.58cdn.com.cn/IjGfEdCbIlr/ishare/d35a35d3XdWbV9Wc5a37XU35d1d359Wc.zip
本文分享自微信公众号 - 58技术(architects_58)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。