最近翻看张鑫旭大佬的博客,发现了一篇叫《前端原生API实现条形码二维码的JS解析识别》的文章,觉得很不错,于是就把大佬的代码拷贝下来学习了下,结果看的我一脸懵,自信心很受打击。痛定思痛,于是把其中觉得有意思的地方记录下,整理成此文。
我们先看下页面是怎么样的:
功能很简单,就是复制下面的二维码图片,然后粘贴到文本框中,且显示在框的正中间,最后点击识别按钮,把识别二维码的结果展示到下面。
源代码:
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8" />
meta http-equiv="X-UA-Compatible" content="IE=edge" />
meta name="viewport" content="width=device-width, initial-scale=1.0" />
title>qrcodetitle>
style>
.area {
height: 200px;
border: 1px dashed skyblue;
background-color: #fff;
display: grid;
place-items: center;
margin-top: 20px;
}
.area:focus {
border-style: solid;
}
.area:empty::before {
content: '或粘贴图片到这里';
color: gray;
}
.button {
margin: 1rem auto;
width: 160px;
height: 40px;
font-size: 112.5%;
background-color: #eb4646;
color: #fff;
border: 0;
border-radius: 0.25rem;
margin-top: 1.5rem;
}
style>
head>
body>
div class="container">
input id="file" class="file" type="file" accept="image/png" />
div id="area" class="area" tabindex="-1">div>
div>
p align="center">
button id="button" class="button">识别button>
p>
p id="result" align="center">p>
p align="center">
方便大家复制的示意图:br />img
src="./qrcode.png"
style="margin-top: 10px"
/>
p>
script>
var reader = new FileReader()
reader.onload = function (event) {
area.innerHTML = 'target.result + '">'
}
document.addEventListener('paste', function (event) {
var items = event.clipboardData && event.clipboardData.items
var file = null
if (items && items.length) {
// 检索剪切板items
for (var i = 0; i length; i++) {
if (items[i].type.indexOf('image') !== -1) {
file = items[i].getAsFile()
break
}
}
}
// 此时file就是剪切板中的图片文件
if (file) {
reader.readAsDataURL(file)
}
})
file.addEventListener('change', function (event) {
const file = event.target.files && event.target.files[0]
if (file) {
reader.readAsDataURL(file)
}
})
button.addEventListener('click', function () {
if ('BarcodeDetector' in window) {
// 创建检测器
const barcodeDetector = new BarcodeDetector({
formats: ['qr_code']
})
const eleImg = document.querySelector('#area img')
if (eleImg) {
barcodeDetector
.detect(eleImg)
.then(barcodes => {
console.log('barcodes', barcodes)
barcodes.forEach(barcode => {
result.innerHTML = `解析成功,结果是:${barcode.rawValue}`
})
})
.catch(err => {
result.innerHTML = `解析出错:${err}`
})
} else {
result.innerHTML = `请先粘贴二维码图片`
}
} else {
result.innerHTML = `当前浏览器不支持二维码识别`
}
})
script>
body>
html>
背景交代完成,现在就来一点点的分析代码的精妙之处。
CSS
部分
tabindex = -1
当我看到tabindex
这个属性时,完全不知道它的用法,于是我继续在张鑫旭大佬的博客中搜索,找到一篇叫《HTML tabindex属性与web网页键盘无障碍访问》的文章,这里简要说下这个属性的用法和作用。
tabindex
是一个与键盘访问行为息息相关的属性,它是一个全局属性,即所有 HTML 标签都可以用的属性,比如id
,class
等属性。因此,它就可以在div
上使用。另外,这个属性没有兼容性问题,放心使用。
我们平常可能感觉不到它的价值,但是一旦我们的鼠标坏掉了或者没电了,我们就只能使用键盘来操作。亦或者在电视机上,或者投影设备上访问我们的网页的时候,我们只能使用遥控器上的按钮,可以看出是电脑的键盘。就算设备都完全正常,对于资深用户而言,键盘访问可以大大提高我们的使用效率。
当一个元素设置tabindex
属性值为-1
的时候,元素会变得focusable
。focusable
指的是元素可以被鼠标 或者 JS focus
,在 chrome 浏览器下表现为会有outline
发光效果,IE浏览器下是虚框,同时能够响应focus
事件。
默认的focusable
元素有,
, 。
但是,tabindex = -1
不能被键盘的tab
键进行focus
。这种鼠标可以focus
,但是键盘却不能focus
的状态,只要tabindex
属性值为负值就可以了。
因此,代码中利用了这一特性,设置div
被focus
的样式,当鼠标点击div
时,我们可以改变它的边框,如下:
.area:focus {
border-style: solid;
}
tabindex
属性值是一个整数,它是用来决定被tab
键focus
的顺序,顺序越小越先被focus
,但是 0
除外,如下div
被focus
的顺序依次是:1,2,3。
div class=“area” tabindex=“3”>div> div class=“area” tabindex=“2”>div>
那tabindex="0"
又是怎么回事呢?
元素设置tabindex="-1"
,可以鼠标和 JS 可以focus
,但键盘不能focus
。
tabindex="0"
和tabindex="-1"
的唯一区别就是键盘也能focus
,但是被focus
的顺序是最后的,也就是当你使用tab
进行聚焦时,最后才会聚集到tabindex="0"
的元素。
设置了tabindex="0"
,从键盘访问的角度来讲,相对于
元素变成了元素。
垂直居中
垂直居中是一个常用的需求了,我经常使用flex
来完成:
display: flex;
align-items: center;
justify-content: center;
在大佬的文章中使用了一个新的用法:
display: grid;
place-items: center;
place-items
属性是以下属性的简写:align-items
、justify-items
。
这样当粘贴图片时,图片就居中显示了。
:empty::before
当div
元素没有内容时,.area:empty
样式会生效,同时为了显示一段提示内容,使用了伪元素::before
,在content
写入提示内容。
.area:empty::before {
content: '或粘贴图片到这里';
color: gray;
}
这个 css 样式平时用的少,所以这里特意的记录下,以免自己忘记。
JS
部分
copy
paste
事件
document.addEventListener('paste', function (event) {
var items = event.clipboardData && event.clipboardData.items
var file = null
if (items && items.length) {
// 检索剪切板items
for (var i = 0; i length; i++) {
if (items[i].type.indexOf('image') !== -1) {
file = items[i].getAsFile()
break
}
}
}
// 此时file就是剪切板中的图片文件
if (file) {
reader.readAsDataURL(file)
}
})
这两个事件都属于ClipboardEvent事件(剪切板事件),还有一个cut
剪切事件。
wrap.oncopy = function(event){}
wrap.oncut = function(event){}
wrap.onpaste = function(event) {}
目前,大部分软件上的内容都是可以被复制粘贴的,这是因为软件对操作系统复制粘贴操作的实现,软件都会把复制剪切的内容存入操作系统的剪切板上。同样,浏览器也对操作系统的复制剪切板进行了实现,属于浏览器的自身的实现。
浏览器复制剪切的默认行为是触发浏览器的 copy 事件,将 copy 的内容存入操作系统的剪切板中。
那如何干预浏览器的这种默认的复制粘贴操作呢?
可以通过event.preventDefault
阻止事件的默认行为,即当触发这三个事件时,阻止对系统剪切板的数据操作。然后,我们对数据进行加工后,重新写入到剪贴板。
比如,当用户复制我们网站的内容时,可以在数据后面加一个版权的相关信息。
script> var wrap = document.getElementById(‘wrap’) wrap.oncopy = function (event) { // 通过copy事件监听,阻止将选中内容复制到系统剪切板上 event.preventDefault() // 获取选中内容对象 const selection = document.getSelection() // selection对象重构了toSring()方法,获取selection对象的选中内容 var selectContent = selection.toString() var dealContent = selectContent + ‘转载请联系作者,内容地址:xxxxx’ // 把重写后的内容写入到剪贴板 event.clipboardData.setData(‘text/plain’, dealContent) } script>
ClipboardEvent
事件有个最重要的属性clipboardData
,该属性值是DataTransfer
对象,这个对象在拖拽场景中经常使用,后面会专门写一篇文章来说说这个对象。
new BarcodeDetector
解析二维码
// 创建检测器
const barcodeDetector = new BarcodeDetector({
formats: ['qr_code']
})
barcodeDetector.detect(eleImg)
.then(barcodes => {
console.log('barcodes', barcodes)
barcodes.forEach(barcode => {
result.innerHTML = `解析成功,结果是:${barcode.rawValue}`
})
})
.catch(err => {
result.innerHTML = `解析出错:${err}`
})
浏览器提供了原生的API来解析二维码和条形码,即 Barcode Detection API
。
formats
表示要解析那种码,如下图所示:
这个 API
有一些兼容性的问题,在生成环境中还是尽量使用第三方库。
但是,作为前端开发,也应该时刻关注浏览器的发展,尽早的使用上最新好用的功能。
总结
通过学习上面的代码,可以发现自己在 css,js 方面上的不足,原因是缺乏探索性,老是用已有的知识来解决问题,或者直接去 github 上找第三方库,其实可以使用最简单的方式实现。
友情链接:
文章来源于互联网:从一篇前端大佬文章中我学到了很多