笔记:前端v实现扫码功能,不使用组件
安装插件npm install html5-qrcodenpm install jsqr代码template div v-ifshowScanner classscanner-overlay div classscanner-modal div classscanner-header span classscanner-title扫码/span button classscanner-close clickcloseScanner×/button /div div classscanner-body div idqr-reader classqr-reader-container/div div v-ifscanResult classscanner-result h3扫描结果/h3 p{{ scanResult }}/p /div /div /div /div /template script setup /* 摄像头组件 */ import { Html5QrcodeScanner } from html5-qrcode; const scanResult ref(); const showScanner ref(false); let html5QrcodeScanner null; // 扫码成功回调 const onScanSuccess (decodedText, decodedResult) { console.log(扫码成功: ${decodedText}, decodedResult); }; // 初始化扫描器 const initializeScanner () { showScanner.value true; nextTick(() { html5QrcodeScanner new Html5QrcodeScanner( qr-reader, { fps: 10, qrbox: { width: 250, height: 250 } }, false ); html5QrcodeScanner.render(onScanSuccess); startObserver(); setTimeout(() { replaceEnglishButtons(); }, 500); }); }; /* 关闭摄像头 */ const closeScanner () { showScanner.value false; scanResult.value ; stopObserver(); if (html5QrcodeScanner) { html5QrcodeScanner.clear(); html5QrcodeScanner null; } }; let observer null; const replaceEnglishButtons () { const elements document.querySelectorAll(.html5-qrcode-element, #qr-reader button, #qr-reader input, #qr-reader span); elements.forEach(el { const text el.textContent.trim().toLowerCase(); if (text.includes(start) || text.includes(camera)) { el.textContent 开启摄像头; } else if (text.includes(stop)) { el.textContent 停止扫描; } else if (text.includes(switch)) { el.textContent 切换摄像头; } else if (text.includes(upload) || text.includes(image) || text.includes(file) || text.includes(select) || text.includes(choose) || text.includes(browse) || text.includes(gallery)) { el.textContent 上传图片; } else if (text.includes(back) || text.includes(cancel)) { el.textContent 返回; } else if (text.includes(try again)) { el.textContent 重试; } }); }; const startObserver () { const container document.getElementById(qr-reader); if (container !observer) { observer new MutationObserver((mutations) { mutations.forEach(() { replaceEnglishButtons(); }); }); observer.observe(container, { childList: true, subtree: true }); } }; const stopObserver () { if (observer) { observer.disconnect(); observer null; } }; /* 窗口关闭时关闭摄像头 */ onBeforeUnmount(() { stopObserver(); if (html5QrcodeScanner) { html5QrcodeScanner.clear(); } }); /* 摄像头组件 */ style scoped video { width: 100%; max-width: 500px; height: auto; } .scanner-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); z-index: 2000; display: flex; align-items: center; justify-content: center; } .scanner-modal { width: 90%; max-width: 500px; background: #FFFFFF; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); } .scanner-header { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; background: #007AFF; } .scanner-title { font-size: 18px; font-weight: bold; color: #FFFFFF; } .scanner-close { width: 32px; height: 32px; background: rgba(255, 255, 255, 0.2); border: none; border-radius: 50%; color: #FFFFFF; font-size: 24px; cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1; transition: background 0.2s; } .scanner-close:hover { background: rgba(255, 255, 255, 0.3); } .scanner-body { padding: 20px; display: flex; flex-direction: column; align-items: center; } .qr-reader-container { width: 100%; max-width: 400px; border-radius: 8px; overflow: hidden; } .scanner-result { margin-top: 20px; padding: 15px; background: #EBF5FC; border-radius: 8px; width: 100%; max-width: 400px; } .scanner-result h3 { margin: 0 0 10px 0; font-size: 16px; color: #007AFF; } .scanner-result p { margin: 0; font-size: 14px; color: #333; word-break: break-all; } /style代码如上可以封装。开启摄像头需要调用initializeScanner()来初始化