1.使用mediadevices api獲取視頻流并顯示在頁(yè)面上;2.使用第三方庫(kù)解析二維碼;3.處理掃描結(jié)果。首先,通過(guò)navigator.mediadevices.getusermedia請(qǐng)求攝像頭權(quán)限并獲取視頻流,將其賦值給video元素的srcobject屬性以顯示畫(huà)面。接著,引入JSqr等第三方庫(kù),將視頻幀繪制到canvas上并提取圖像數(shù)據(jù)進(jìn)行二維碼解析。最后,當(dāng)解析成功時(shí),將結(jié)果展示在頁(yè)面或彈窗中,可選擇跳轉(zhuǎn)鏈接或執(zhí)行其他操作,并注意安全檢查。
二維碼掃描這件事,聽(tīng)起來(lái)高大上,其實(shí)用瀏覽器自帶的bom(瀏覽器對(duì)象模型)也能搞定個(gè)七七八八。關(guān)鍵不在于實(shí)現(xiàn)一個(gè)完美的掃描器,而在于理解瀏覽器能提供哪些能力,以及如何巧妙地利用它們。
mediaDevices API 提供了一種訪問(wèn)用戶(hù)攝像頭的方式,配合一些二維碼解析庫(kù),就能在網(wǎng)頁(yè)上實(shí)現(xiàn)基本的二維碼掃描功能。
mediaDevices API的使用和權(quán)限請(qǐng)求 如何獲取視頻流并顯示在頁(yè)面上? 使用第三方庫(kù)解析二維碼 如何處理掃描結(jié)果?
mediaDevices API的使用和權(quán)限請(qǐng)求
首先,mediaDevices API 是核心。它允許我們?cè)L問(wèn)用戶(hù)的攝像頭。但要注意,訪問(wèn)攝像頭需要用戶(hù)授權(quán)。所以,第一步是檢查瀏覽器是否支持 mediaDevices,然后發(fā)起權(quán)限請(qǐng)求。
navigator.mediaDevices.getUserMedia({ video: true }) .then(stream => { // 成功獲取視頻流 const video = document.createElement('video'); video.srcObject = stream; video.play(); // 將視頻流顯示在頁(yè)面上,例如添加到某個(gè) div 中 const videoContainer = document.getElementById('video-container'); videoContainer.appendChild(video); }) .catch(error => { // 用戶(hù)拒絕授權(quán)或發(fā)生其他錯(cuò)誤 console.error("無(wú)法訪問(wèn)攝像頭:", error); alert("請(qǐng)?jiān)试S訪問(wèn)攝像頭,才能使用二維碼掃描功能。"); });
這段代碼首先嘗試獲取視頻流。如果用戶(hù)允許訪問(wèn)攝像頭,getUserMedia 會(huì)返回一個(gè) stream 對(duì)象,我們可以將這個(gè) stream 賦值給一個(gè) video 元素的 srcObject 屬性,然后播放視頻。如果用戶(hù)拒絕授權(quán),或者發(fā)生其他錯(cuò)誤,catch 塊會(huì)捕獲錯(cuò)誤并給出提示。
需要注意的是,不同瀏覽器對(duì) getUserMedia 的實(shí)現(xiàn)可能略有差異,需要做一些兼容性處理。另外,權(quán)限請(qǐng)求通常只能在 https 環(huán)境下發(fā)起,否則瀏覽器會(huì)阻止。
如何獲取視頻流并顯示在頁(yè)面上?
上面已經(jīng)展示了如何獲取視頻流并顯示在頁(yè)面上。但這里可以再展開(kāi)一下。video 元素是關(guān)鍵,它負(fù)責(zé)顯示攝像頭的畫(huà)面。我們可以通過(guò) css 來(lái)控制 video 元素的大小和位置,使其適應(yīng)頁(yè)面布局。
另外,為了提高用戶(hù)體驗(yàn),可以添加一些控制按鈕,例如暫停/播放、切換攝像頭等。這些按鈕可以通過(guò) JavaScript 來(lái)控制 video 元素的 play() 和 pause() 方法,以及通過(guò) getUserMedia 的 deviceId 選項(xiàng)來(lái)切換攝像頭。
<div id="video-container"> <video autoplay playsinline width="640" height="480"></video> </div> <button id="toggle-camera">切換攝像頭</button> <script> const video = document.querySelector('video'); const toggleCameraBtn = document.getElementById('toggle-camera'); let currentStream; let currentDeviceId; function startCamera(deviceId) { const constraints = { video: { deviceId: deviceId ? { exact: deviceId } : undefined } }; navigator.mediaDevices.getUserMedia(constraints) .then(stream => { if (currentStream) { currentStream.getTracks().forEach(track => track.stop()); } currentStream = stream; video.srcObject = stream; currentDeviceId = deviceId; }) .catch(err => console.error('Error Accessing camera:', err)); } navigator.mediaDevices.enumerateDevices() .then(devices => { const cameras = devices.filter(device => device.kind === 'videoinput'); if (cameras.length > 0) { startCamera(cameras[0].deviceId); // 默認(rèn)啟動(dòng)第一個(gè)攝像頭 if (cameras.length > 1) { toggleCameraBtn.addEventListener('click', () => { const nextCameraIndex = (cameras.findIndex(cam => cam.deviceId === currentDeviceId) + 1) % cameras.length; startCamera(cameras[nextCameraIndex].deviceId); }); } else { toggleCameraBtn.disabled = true; // 只有一個(gè)攝像頭,禁用切換按鈕 } } else { console.warn('No cameras found.'); } }) .catch(err => console.error('Error enumerating devices:', err)); </script>
使用第三方庫(kù)解析二維碼
有了視頻流,接下來(lái)就是解析二維碼了。瀏覽器本身沒(méi)有提供二維碼解析的功能,所以我們需要借助第三方庫(kù)。比較流行的選擇有 jsQR 和 zxing-js。這里以 jsQR 為例:
首先,引入 jsQR 庫(kù):
<script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js"></script>
然后,我們需要將視頻幀轉(zhuǎn)換為 jsQR 可以處理的格式。通常的做法是將視頻幀繪制到 Canvas 上,然后從 Canvas 中提取圖像數(shù)據(jù)。
const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); function scanQRCode() { canvas.width = video.videoWidth; canvas.height = video.videoHeight; context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { console.log("Found QR code", code.data); // 處理掃描結(jié)果 } else { // 沒(méi)有找到二維碼 requestAnimationFrame(scanQRCode); // 繼續(xù)掃描 } } video.addEventListener('loadedmetadata', () => { scanQRCode(); // 開(kāi)始掃描 });
這段代碼首先創(chuàng)建一個(gè) Canvas 元素,然后將視頻幀繪制到 Canvas 上。接著,從 Canvas 中提取圖像數(shù)據(jù),并使用 jsQR 解析二維碼。如果找到二維碼,jsQR 會(huì)返回一個(gè)包含二維碼數(shù)據(jù)的對(duì)象,否則返回 NULL。
為了持續(xù)掃描,我們使用 requestAnimationFrame 在每一幀都調(diào)用 scanQRCode 函數(shù)。當(dāng)視頻加載完成后,我們開(kāi)始掃描。
如何處理掃描結(jié)果?
當(dāng) jsQR 成功解析二維碼后,我們就可以處理掃描結(jié)果了。最常見(jiàn)的做法是將二維碼數(shù)據(jù)展示給用戶(hù),或者根據(jù)二維碼數(shù)據(jù)進(jìn)行跳轉(zhuǎn)或其他操作。
if (code) { console.log("Found QR code", code.data); alert("掃描結(jié)果: " + code.data); // 可以將掃描結(jié)果顯示在頁(yè)面上 const resultDiv = document.getElementById('result'); resultDiv.textContent = "掃描結(jié)果: " + code.data; // 或者根據(jù)掃描結(jié)果進(jìn)行跳轉(zhuǎn) // window.location.href = code.data; }
這段代碼首先將二維碼數(shù)據(jù)打印到控制臺(tái),然后彈出一個(gè)提示框顯示掃描結(jié)果。你也可以將掃描結(jié)果顯示在頁(yè)面上的某個(gè)元素中,或者根據(jù)掃描結(jié)果進(jìn)行跳轉(zhuǎn)。
需要注意的是,二維碼數(shù)據(jù)可能包含惡意鏈接或代碼,所以在進(jìn)行跳轉(zhuǎn)或其他操作時(shí),一定要進(jìn)行安全檢查。
總的來(lái)說(shuō),用 BOM 實(shí)現(xiàn)二維碼掃描并不復(fù)雜,關(guān)鍵在于理解瀏覽器提供的 API,以及如何巧妙地利用它們。當(dāng)然,這種方式實(shí)現(xiàn)的二維碼掃描功能比較基礎(chǔ),可能無(wú)法滿(mǎn)足所有需求。如果需要更高級(jí)的功能,例如更快的掃描速度、更強(qiáng)的容錯(cuò)能力等,可能需要使用更專(zhuān)業(yè)的二維碼掃描庫(kù)或 Native API。