从张鑫旭大佬文章中发现了我前端知识的匮乏

最近翻看张鑫旭大佬的博客,发现了一篇叫《前端原生API实现条形码二维码的JS解析识别》[1]的文章,觉得很不错,于是就把大佬的代码拷贝下来学习了下,结果就是看的我一脸懵,自信息大大受打击了。痛定思痛,于是把其中觉得有意思的地方记录下,整理成此文。

我们先看下页面是怎么样的:

70e957f5d643de652c72917c7faac506.jpeg
chrome-capture-2023-5-26.gif

功能很简单,就是复制下面的二维码图片,然后粘贴到文本框中,最后点击识别按钮,把识别二维码的结果展示到下面。

源代码:

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>qrcode</title>
    <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 = '<img src="' + event.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 < items.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 = `<span class="success">解析成功,结果是:</span>${barcode.rawValue}`
                })
              })
              .catch(err => {
                result.innerHTML = `<span class="error">解析出错:${err}</span>`
              })
          } else {
            result.innerHTML = `<span class="error">请先粘贴二维码图片</span>`
          }
        } else {
          result.innerHTML = `<span class="error">当前浏览器不支持二维码识别</span>`
        }
      })
    </script>
  </body>
</html>

背景交代完成,现在就一点一点的来分析其中代码的精妙之处。

CSS部分

tabindex = -1

js
复制代码
<div id="area" class="area" tabindex="-1"></div>

当我看到tabindex这个属性时,完全不知道它的用法,于是我继续在张鑫旭大佬的博客中搜索,找到一篇叫《HTML tabindex属性与web网页键盘无障碍访问》[2]的文章,这里简要说下这个属性的用法和作用。

tabindex属性是一个全局属性,也就是所有 HTML 标签都可以用的属性,比方说idclass属性等。所以,可以在div上使用。同时,这个属性是一个非常老的属性,没有兼容性问题,放心使用。

tabindex属性是一个与键盘访问行为息息相关的属性。平常可能感觉不到它的价值,但是一旦我们的鼠标坏掉了或者没电了,我们就只能使用键盘。亦或者在电视机上,或者投影设备上访问我们的网页的时候,我们只能使用遥控器。就算设备都完全正常,对于资深用户而言,键盘访问可以大大提高我们的使用效率。

当一个元素设置tabindex属性值为-1的时候,元素会变得focusable,所谓focusable指的是元素可以被鼠标或者JS focus,在 Chrome 浏览器下表现为会有outline发光效果,IE浏览器下是虚框,同时能够响应focus事件。默认的focusable元素有<a>, <area>, <button>, <input>, <object>, <select> 以及 <textarea>

但是,tabindex = -1不能被键盘的tab键进行focus。这种鼠标可以focus,但是键盘却不能focus的状态,只要tabindex属性值为负值就可以了。

因此,我们可以设置divfocus的样式,当鼠标点击div时,我们可以改变它的边框,如下:

js
复制代码
.area:focus {
    border-style: solid;
 }

tabindex属性值是一个整数,它来决定被tabfocus的顺序,顺序越小越先被focus,但是 0除外,如下divfocus的顺序依次是:1,2,3。

js
复制代码
<div id="area" class="area" tabindex="1"></div>
<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的顺序是最后的。或者你可以这么理解,<div>设置了tabindex="0",从键盘访问的角度来讲,相对于<div>元素变成了<button>元素。

垂直居中

垂直居中是一个常用的需求了,我经常使用flex来完成:

js
复制代码
display: flex;
align-items: center;
justify-content: center;

在大佬的文章中使用了一个新的用法:

js
复制代码
display: grid;
place-items: center;

place-items 属性是以下属性的简写:align-itemsjustify-items

:empty::before

div元素没有内容时,.area:empty样式会生效,同时为了显示一段提示内容,使用了伪元素::before,在content写入提示内容。

js
复制代码
.area:empty::before {
    content: '或粘贴图片到这里';
    color: gray;
}

JS部分

copy paste 事件

js
复制代码
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 < items.length; i++) {
        if (items[i].type.indexOf('image') !== -1) {
          file = items[i].getAsFile()
          break
        }
      }
    }
    // 此时file就是剪切板中的图片文件
    if (file) {
      reader.readAsDataURL(file)
    }
})

这两个事件都属于ClipboardEvent事件(剪切板事件) ,还有一个cut剪切事件。

js
复制代码
wrap.oncopy = function(event){}
wrap.oncut = function(event){}
wrap.onpaste = function(event) {}

任何软件上的内容,可以被复制粘贴,是因为软件对操作系统复制粘贴操作的实现,软件都会把复制剪切的内容存入操作系统的剪切板上。同样,浏览器也对操作系统的剪切板进行了实现,属于浏览器的自身的实现。

浏览器复制操作的默认行为是触发浏览器的 copy 事件,将 copy 的内容存入操作系统的剪切板中。

那如何干预浏览器的这种默认的复制粘贴操作呢?

可以通过event.preventDefault阻止事件的默认行为,即当触发这三个事件时,阻止对系统剪切板的数据操作。然后,我们对数据进行加工后,重新写入到剪贴板。

比如,当用户复制我们网站的内容时,可以在数据后面加一个版权的相关信息。

js
复制代码
<div id="wrap">这是复制的复制内容</div>
    <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解析二维码

js
复制代码
// 创建检测器
const barcodeDetector = new BarcodeDetector({
    formats: ['qr_code']
})
barcodeDetector.detect(eleImg)
  .then(barcodes => {
    console.log('barcodes', barcodes)
    barcodes.forEach(barcode => {
      result.innerHTML = `<span class="success">解析成功,结果是:</span>${barcode.rawValue}`
    })
  })
  .catch(err => {
    result.innerHTML = `<span class="error">解析出错:${err}</span>`
  })

浏览器提供了原生的API来解析二维码和条形码,即 Barcode Detection API

formats表示要解析那种码,如下图所示:

e8f1534902236273665482d2d5896ece.jpeg
image.png

总结

通过学习上面的代码,可以发现自己在 css,js 方面上的不足,原因是缺乏探索性,老是用已有的知识来解决问题,或者直接去 github 上找第三方库,其实可以使用最简单的方式实现。

作者:小p
链接:https://juejin.cn/post/7248874230862233655
来源:稀土掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值