布讲栗猫劳思 發表於 2024-8-10 10:20:00

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

<p>在数字化时代,二维码已经渗透到我们生活的方方面面。从移动支付到产品溯源,二维码凭借其便捷性和高效性,成为了信息传递的重要载体。而随着前端技术的不断发展,我们甚至可以使用 JavaScript 在网页端实现二维码扫描功能,为用户提供更加便捷的操作体验。</p>
<p>本文将带您深入了解如何使用 JavaScript 调用摄像头,结合&nbsp;<code>jsQR</code>&nbsp;库,以及如何控制闪光灯,最终实现一个功能完善的网页扫码应用。</p>
<h3>一、 项目概述</h3>
<p>我们将创建一个简单的网页应用,该应用能够:</p>
<ol>
<li>调用设备摄像头,获取实时视频流。</li>
<li>在网页上创建一个扫描区域,用户可以将二维码放置在该区域内进行扫描。</li>
<li>使用&nbsp;<code>jsQR</code>&nbsp;库解码扫描区域内的二维码图像数据,获取二维码内容。</li>
<li>提供手动输入二维码内容的功能。</li>
<li>如果设备支持,还可以控制闪光灯的开关,以便在光线不足的情况下进行扫描。</li>
</ol>
<h3>二、 实现步骤</h3>
<h4>1. HTML 结构</h4>
<p>首先,我们需要构建基本的 HTML 结构,包括:</p>
<ul>
<li><code>&lt;video&gt;</code>&nbsp;标签:用于展示摄像头捕获的实时视频流。</li>
<li><code>&lt;canvas&gt;</code>&nbsp;标签:用于绘制视频帧和扫描区域,并从中获取图像数据。</li>
<li><code>&lt;div&gt;</code>&nbsp;标签:用于创建扫描区域、按钮组等 UI 元素。</li>
</ul>
<div class="pre-all-wrapper">
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
&lt;title&gt;扫一扫&lt;/title&gt;
&lt;link rel="stylesheet" href="style.css"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;video id="video" autoplay&gt;&lt;/video&gt;
&lt;canvas id="overlay" hidden&gt;&lt;/canvas&gt;

&lt;div class="scan-area"&gt;&lt;/div&gt;

&lt;div class="btn-group"&gt;
    &lt;button id="manualInputBtn"&gt;手动输入&lt;/button&gt;
    &lt;button id="flashBtn"&gt;闪光灯&lt;/button&gt;
&lt;/div&gt;

&lt;script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"&gt;&lt;/script&gt;
&lt;script src="script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
</div>
<h4>2. CSS 样式</h4>
<p>为了提升用户体验,我们需要为页面元素添加一些样式:</p>
<div class="pre-all-wrapper">
<pre><code class="language-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%;
}

/* ...其他样式 */
</code></pre>
</div>
<h4>3. JavaScript 交互</h4>
<p>JavaScript 代码是实现扫码功能的核心部分,主要包括以下几个步骤:</p>
<ol>
<li>
<p>获取摄像头权限:&nbsp;使用&nbsp;<code>navigator.mediaDevices.getUserMedia()</code>&nbsp;方法请求访问用户的摄像头。</p>
</li>
<li>
<p>播放视频流:&nbsp;将获取到的视频流赋值给&nbsp;<code>&lt;video&gt;</code>&nbsp;标签的&nbsp;<code>srcObject</code>&nbsp;属性,并调用&nbsp;<code>video.play()</code>&nbsp;方法开始播放。</p>
</li>
<li>
<p>创建扫描循环:&nbsp;使用&nbsp;<code>requestAnimationFrame()</code>&nbsp;方法创建一个循环,不断地从视频流中获取帧图像,并进行二维码解码。</p>
</li>
<li>
<p>绘制视频帧:&nbsp;在每一帧中,使用&nbsp;<code>canvas.drawImage()</code>&nbsp;方法将视频帧绘制到&nbsp;<code>&lt;canvas&gt;</code>&nbsp;元素上。</p>
</li>
<li>
<p>获取扫描区域图像数据:&nbsp;使用&nbsp;<code>canvas.getImageData()</code>&nbsp;方法获取扫描区域的图像数据。</p>
</li>
<li>
<p>解码二维码:&nbsp;使用&nbsp;<code>jsQR</code>&nbsp;库的&nbsp;<code>jsQR()</code>&nbsp;方法解码图像数据,如果解码成功,则获取二维码内容。</p>
</li>
<li>
<p>处理扫描结果:&nbsp;对解码后的二维码内容进行处理,例如跳转到链接、显示信息等。</p>
</li>
<li>
<p>实现其他功能:&nbsp;实现手动输入二维码内容和控制闪光灯等功能。</p>
</li>
</ol>
<div class="pre-all-wrapper">
<pre><code class="language-javascript">// 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 =&gt; {
    stream = s;
    video.srcObject = stream;
    video.play();

    // 开始扫描
    scanning = true;
    requestAnimationFrame(scan);
})
.catch(err =&gt; {
    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() {
// ...
});
</code></pre>
</div>
<h3>三、完整代码</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:html;gutter:true;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
&lt;title&gt;扫一扫&lt;/title&gt;
&lt;style&gt;
    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;
    }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;video id="video" autoplay&gt;&lt;/video&gt;
&lt;canvas id="overlay" hidden&gt;&lt;/canvas&gt;

&lt;div class="scan-area"&gt;&lt;/div&gt;

&lt;div class="btn-group"&gt;
&lt;button id="manualInputBtn"&gt;手动输入&lt;/button&gt;
&lt;button id="flashBtn"&gt;闪光灯&lt;/button&gt;
&lt;/div&gt;

&lt;script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
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().applyConstraints({
      advanced: [{ torch: flashEnabled }]
      });

      // 更新按钮文本
      flashBtn.textContent = flashEnabled ? '关闭闪光灯' : '闪光灯';
    } else {
      alert('您的设备不支持闪光灯功能。');
    }
});

// 开始扫描
scanning = true;
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt; </pre>
</div>
<h3>四、 总结</h3>
<p>通过以上步骤,我们成功地使用 JavaScript 在网页端实现了二维码扫描功能。该功能可以广泛应用于各种场景,例如:</p>
<ul>
<li>移动支付:&nbsp;用户可以使用手机扫描网页上的二维码完成支付。</li>
<li>产品溯源:&nbsp;用户可以扫描产品上的二维码,查看产品信息、生产日期、物流信息等。</li>
<li>活动签到:&nbsp;用户可以使用手机扫描二维码完成活动签到。</li>
</ul>
<p>随着 Web 技术的不断发展,相信未来会有更多创新的应用场景出现。</p>
<p>希望本文能够帮助您了解网页扫码功能的实现原理,并激发您探索更多前端黑科技的兴趣。</p><br><br>
来源:https://www.cnblogs.com/geekcjj/p/18352006
頁: [1]
查看完整版本: 前端黑科技:使用 JavaScript 实现网页扫码功能