在數字化時代,二維碼已經滲透到我們生活的方方面面。從移動支付到產品溯源,二維碼憑藉其便捷性和高效性,成為了資訊傳遞的重要載體。而隨著前端技術的不斷髮展,我們甚至可以使用 JavaScript 在網頁端實現二維碼掃描功能,為使用者提供更加便捷的操作體驗。
本文將帶您深入瞭解如何使用 JavaScript 呼叫攝像頭,結合 jsQR
庫,以及如何控制閃光燈,最終實現一個功能完善的網頁掃碼應用。
一、 專案概述
我們將建立一個簡單的網頁應用,該應用能夠:
- 呼叫裝置攝像頭,獲取實時影片流。
- 在網頁上建立一個掃描區域,使用者可以將二維碼放置在該區域內進行掃描。
- 使用
jsQR
庫解碼掃描區域內的二維碼影像資料,獲取二維碼內容。 - 提供手動輸入二維碼內容的功能。
- 如果裝置支援,還可以控制閃光燈的開關,以便在光線不足的情況下進行掃描。
二、 實現步驟
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 程式碼是實現掃碼功能的核心部分,主要包括以下幾個步驟:
-
獲取攝像頭許可權: 使用
navigator.mediaDevices.getUserMedia()
方法請求訪問使用者的攝像頭。 -
播放影片流: 將獲取到的影片流賦值給
<video>
標籤的srcObject
屬性,並呼叫video.play()
方法開始播放。 -
建立掃描迴圈: 使用
requestAnimationFrame()
方法建立一個迴圈,不斷地從影片流中獲取幀影像,並進行二維碼解碼。 -
繪製影片幀: 在每一幀中,使用
canvas.drawImage()
方法將影片幀繪製到<canvas>
元素上。 -
獲取掃描區域影像資料: 使用
canvas.getImageData()
方法獲取掃描區域的影像資料。 -
解碼二維碼: 使用
jsQR
庫的jsQR()
方法解碼影像資料,如果解碼成功,則獲取二維碼內容。 -
處理掃描結果: 對解碼後的二維碼內容進行處理,例如跳轉到連結、顯示資訊等。
-
實現其他功能: 實現手動輸入二維碼內容和控制閃光燈等功能。
// 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() {
// ...
});
三、完整程式碼
<!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 技術的不斷髮展,相信未來會有更多創新的應用場景出現。
希望本文能夠幫助您瞭解網頁掃碼功能的實現原理,並激發您探索更多前端黑科技的興趣。