前端黑科技:使用 JavaScript 实现网页扫码功能

在数字化时代,二维码已经渗透到我们生活的方方面面。从移动支付到产品溯源,二维码凭借其便捷性和高效性,成为了信息传递的重要载体。而随着前端技术的不断发展,我们甚至可以使用 JavaScript 在网页端实现二维码扫描功能,为用户提供更加便捷的操作体验。

本文将带您深入了解如何使用 JavaScript 调用摄像头,结合 jsQR 库,以及如何控制闪光灯,最终实现一个功能完善的网页扫码应用。

一、 项目概述

我们将创建一个简单的网页应用,该应用能够:

  1. 调用设备摄像头,获取实时视频流。
  2. 在网页上创建一个扫描区域,用户可以将二维码放置在该区域内进行扫描。
  3. 使用 jsQR 库解码扫描区域内的二维码图像数据,获取二维码内容。
  4. 提供手动输入二维码内容的功能。
  5. 如果设备支持,还可以控制闪光灯的开关,以便在光线不足的情况下进行扫描。

二、 实现步骤

1. HTML 结构

首先,我们需要构建基本的 HTML 结构,包括:

  • <video> 标签:用于展示摄像头捕获的实时视频流。
  • <canvas> 标签:用于绘制视频帧和扫描区域,并从中获取图像数据。
  • <div> 标签:用于创建扫描区域、按钮组等 UI 元素。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>扫一扫</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <video id="video" autoplay></video>
  <canvas id="overlay" hidden></canvas>

  <div class="scan-area"></div>

  <div class="btn-group">
    <button id="manualInputBtn">手动输入</button>
    <button id="flashBtn">闪光灯</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script>
  <script src="script.js"></script>
</body>
</html>
2. CSS 样式

为了提升用户体验,我们需要为页面元素添加一些样式:

/* style.css */
body {
  margin: 0;
  overflow: hidden;
}

#video {
  width: 100%;
  height: auto;
  display: block;
}

#overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.scan-area {
  border: 3px solid yellow;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 80%;
  height: 30%;
}

/* ...其他样式 */
3. JavaScript 交互

JavaScript 代码是实现扫码功能的核心部分,主要包括以下几个步骤:

  1. 获取摄像头权限: 使用 navigator.mediaDevices.getUserMedia() 方法请求访问用户的摄像头。

  2. 播放视频流: 将获取到的视频流赋值给 <video> 标签的 srcObject 属性,并调用 video.play() 方法开始播放。

  3. 创建扫描循环: 使用 requestAnimationFrame() 方法创建一个循环,不断地从视频流中获取帧图像,并进行二维码解码。

  4. 绘制视频帧: 在每一帧中,使用 canvas.drawImage() 方法将视频帧绘制到 <canvas> 元素上。

  5. 获取扫描区域图像数据: 使用 canvas.getImageData() 方法获取扫描区域的图像数据。

  6. 解码二维码: 使用 jsQR 库的 jsQR() 方法解码图像数据,如果解码成功,则获取二维码内容。

  7. 处理扫描结果: 对解码后的二维码内容进行处理,例如跳转到链接、显示信息等。

  8. 实现其他功能: 实现手动输入二维码内容和控制闪光灯等功能。

// script.js
const video = document.getElementById('video');
const overlay = document.getElementById('overlay');
const manualInputBtn = document.getElementById('manualInputBtn');
const flashBtn = document.getElementById('flashBtn');
const scanArea = document.querySelector('.scan-area');

let stream;
let scanning = false;
let flashEnabled = false;

// 获取摄像头权限并开始播放视频流
navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
  .then(s => {
    stream = s;
    video.srcObject = stream;
    video.play();

    // 开始扫描
    scanning = true;
    requestAnimationFrame(scan);
  })
  .catch(err => {
    console.error("无法访问摄像头:", err);
  });

// 扫描二维码
function scan() {
  if (scanning) {
    const canvas = overlay.getContext('2d');
    const videoWidth = video.videoWidth;
    const videoHeight = video.videoHeight;

    // 设置画布大小
    overlay.width = videoWidth;
    overlay.height = videoHeight;

    // 将视频帧绘制到画布上
    canvas.drawImage(video, 0, 0, videoWidth, videoHeight);

    // ...获取扫描区域图像数据

    // 使用 jsQR 库解码二维码
    const code = jsQR(imageData.data, imageData.width, imageData.height);

    // 如果成功解码,则停止扫描并处理结果
    if (code) {
      scanning = false;
      handleScanResult(code.data);
    } else {
      requestAnimationFrame(scan);
    }
  }
}

// 处理扫描结果
function handleScanResult(data) {
  alert("扫描结果:" + data);

  // 这里可以根据扫描结果进行相应的操作,例如跳转到链接或显示信息
}

// 手动输入按钮点击事件
manualInputBtn.addEventListener('click', function() {
  // ...
});

// 闪光灯按钮点击事件
flashBtn.addEventListener('click', function() {
  // ...
});

三、完整代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<! DOCTYPE html>
< html >
< head >
   < meta charset="UTF-8">
   < meta name="viewport" content="width=device-width, initial-scale=1.0">
   < title >扫一扫</ title >
   < style >
     body {
       margin: 0;
       overflow: hidden;
     }
 
     #video {
       width: 100%;
       height: auto;
       display: block;
     }
 
     #overlay {
       position: absolute;
       top: 0;
       left: 0;
       width: 100%;
       height: 100%;
       pointer-events: none;
     }
 
     .scan-area {
       border: 3px solid yellow;
       position: absolute;
       top: 50%;
       left: 50%;
       transform: translate(-50%, -50%);
       width: 80%;
       height: 30%;
     }
 
     .btn-group {
       position: absolute;
       bottom: 20px;
       left: 50%;
       transform: translateX(-50%);
       display: flex;
     }
 
     button {
       background-color: rgba(0, 0, 0, 0.5);
       color: white;
       border: none;
       padding: 10px 20px;
       margin: 0 10px;
       border-radius: 5px;
       font-size: 16px;
       cursor: pointer;
     }
   </ style >
</ head >
< body >
 
< video id="video" autoplay></ video >
< canvas id="overlay" hidden></ canvas >
 
< div class="scan-area"></ div >
 
< div class="btn-group">
   < button id="manualInputBtn">手动输入</ button >
   < button id="flashBtn">闪光灯</ button >
</ div >
 
< script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></ script >
< script >
   const video = document.getElementById('video');
   const overlay = document.getElementById('overlay');
   const manualInputBtn = document.getElementById('manualInputBtn');
   const flashBtn = document.getElementById('flashBtn');
   const scanArea = document.querySelector('.scan-area');
 
   let stream;
   let scanning = false;
   let flashEnabled = false;
 
   // 获取摄像头权限并开始播放视频流
   navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
     .then(function(s) {
       stream = s;
       video.srcObject = stream;
       video.play();
 
       // 开始扫描
       requestAnimationFrame(scan);
     })
     .catch(function(err) {
       console.error("无法访问摄像头:", err);
     });
 
   // 扫描二维码
   function scan() {
     if (scanning) {
       const canvas = overlay.getContext('2d');
       const videoWidth = video.videoWidth;
       const videoHeight = video.videoHeight;
 
       // 设置画布大小
       overlay.width = videoWidth;
       overlay.height = videoHeight;
 
       // 将视频帧绘制到画布上
       canvas.drawImage(video, 0, 0, videoWidth, videoHeight);
 
       // 获取扫描区域的坐标和尺寸
       const scanAreaRect = scanArea.getBoundingClientRect();
       const scanAreaX = scanAreaRect.left;
       const scanAreaY = scanAreaRect.top;
       const scanAreaWidth = scanAreaRect.width;
       const scanAreaHeight = scanAreaRect.height;
 
       // 获取扫描区域的图像数据
       const imageData = canvas.getImageData(scanAreaX, scanAreaY, scanAreaWidth, scanAreaHeight);
 
       // 使用 jsQR 库解码二维码
       const code = jsQR(imageData.data, imageData.width, imageData.height);
 
       // 如果成功解码,则停止扫描并处理结果
       if (code) {
         scanning = false;
         handleScanResult(code.data);
       } else {
         requestAnimationFrame(scan);
       }
     }
   }
 
   // 处理扫描结果
   function handleScanResult(data) {
     alert("扫描结果:" + data);
 
     // 这里可以根据扫描结果进行相应的操作,例如跳转到链接或显示信息
   }
 
   // 手动输入按钮点击事件
   manualInputBtn.addEventListener('click', function() {
     const input = prompt("请输入二维码内容:");
     if (input) {
       handleScanResult(input);
     }
   });
 
   // 闪光灯按钮点击事件
   flashBtn.addEventListener('click', function() {
     if ('torch' in navigator.mediaDevices.getUserMedia({ video: true })) {
       flashEnabled = !flashEnabled;
       stream.getVideoTracks()[0].applyConstraints({
         advanced: [{ torch: flashEnabled }]
       });
 
       // 更新按钮文本
       flashBtn.textContent = flashEnabled ? '关闭闪光灯' : '闪光灯';
     } else {
       alert('您的设备不支持闪光灯功能。');
     }
   });
 
   // 开始扫描
   scanning = true;
</ script >
 
</ body >
</ html > 

四、 总结

通过以上步骤,我们成功地使用 JavaScript 在网页端实现了二维码扫描功能。该功能可以广泛应用于各种场景,例如:

  • 移动支付: 用户可以使用手机扫描网页上的二维码完成支付。
  • 产品溯源: 用户可以扫描产品上的二维码,查看产品信息、生产日期、物流信息等。
  • 活动签到: 用户可以使用手机扫描二维码完成活动签到。

随着 Web 技术的不断发展,相信未来会有更多创新的应用场景出现。

希望本文能够帮助您了解网页扫码功能的实现原理,并激发您探索更多前端黑科技的兴趣。

原创作者: geekcjj 转载于: https://www.cnblogs.com/geekcjj/p/18352006
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值