uniapp的H5项目中,实现扫描二维码
·
- 除了 H5 之外的其他环境都可以用 uni.scanCode
- 需要 https 环境
安装:npm install html5-qrcode --save
(样式很随意、很丑,但是能用。)
<template>
<view class="scan-container">
<!-- 扫码区域 -->
<view id="qr-reader" style="width: 100%;"></view>
<!-- 扫描框UI -->
<view class="scan-mask" v-if="isScanning">
<view class="scan-box">
<view class="scan-line" :style="{top: linePosition+'px'}"></view>
</view>
</view>
<!-- 结果展示 -->
<!-- <view v-if="scanResult" class="result-box">
<text>扫描结果: {{ scanResult }}</text>
</view> -->
<!-- 控制按钮 -->
<view class="btn-group">
<button @click="startScan" :disabled="isScanning">开始扫描</button>
<button @click="stopScan" :disabled="!isScanning">停止扫描</button>
</view>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
// #ifdef H5
import { Html5Qrcode } from 'html5-qrcode';
// #endif
export default {
data() {
return {
html5QrCode: null,
isScanning: false,
scanResult: null,
cameraId: null
};
},
mounted() {
// #ifdef H5
this.initScanner();
// #endif
},
beforeDestroy() {
this.stopScan();
},
methods: {
// #ifdef H5
async initScanner() {
try {
// 获取摄像头设备列表
const devices = await Html5Qrcode.getCameras();
if (devices && devices.length > 0) {
// 优先选择后置摄像头
const backCamera = devices.find(device =>
device.label.toLowerCase().includes('back') || device.facingMode === 'environment'
);
// 如果没有找到后置摄像头,则选择前置摄像头
const frontCamera = devices.find(device =>
device.label.toLowerCase().includes('front') || device.facingMode === 'user'
);
// 根据设备选择相应的摄像头, devices[0] 是第一个摄像头/前置摄像。
this.cameraId = backCamera ? backCamera.id : frontCamera ? frontCamera.id : devices[1].id;
} else {
throw new Error('未检测到可用摄像头');
}
} catch (err) {
console.error('摄像头初始化失败:', err);
this.showToast(`摄像头错误: ${err.message}`);
}
},
async startScan() {
if (this.isScanning) return;
try {
this.html5QrCode = new Html5Qrcode("qr-reader");
const config = {
facingMode: "environment", // 明确要求后置摄像头
fps: 20, // 提高帧率,适当提升扫描速度
// qrbox: { width: 250, height: 250 }, // 扫码框大小
aspectRatio: 1.0 // 宽高比
};
await this.html5QrCode.start(
this.cameraId,
config,
this.onScanSuccess,
this.onScanError
);
this.isScanning = true;
this.scanResult = null;
} catch (err) {
console.error('扫码启动失败:', err);
this.showToast(`扫码启动失败: ${err.message}`);
}
},
onScanSuccess(decodedText, decodedResult) {
this.scanResult = decodedText;
// this.showToast(`扫描成功: ${decodedText}`);
this.stopScan();
// 处理扫描结果
this.handleScanResult(decodedText);
},
onScanError(errorMessage) {
// 忽略部分非致命错误
if (!errorMessage.includes('NotFoundException')) {
console.warn('扫码错误:', errorMessage);
}
},
stopScan() {
if (this.html5QrCode && this.isScanning) {
this.html5QrCode.stop()
.then(() => {
this.isScanning = false;
this.html5QrCode.clear();
})
.catch(err => {
console.error('扫码停止失败:', err);
});
}
},
// #endif
handleScanResult(result) {
// 在这里处理扫描结果
uni.showModal({
title: '扫描结果',
content: result,
showCancel: false,
success: (res) => {
console.log('模态框回调:', res);
if (res.confirm) {
uni.navigateBack();
}else{
}
}
});
},
showToast(message) {
this.$refs.uToast.show({
message: message,
type: 'info',
duration: 2000
});
}
}
};
</script>
<style>
.scan-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
#qr-reader {
margin: 20px 0;
border: 2px solid #eee;
border-radius: 8px;
overflow: hidden;
}
.result-box {
margin: 20px;
padding: 15px;
background-color: #f5f5f5;
border-radius: 8px;
width: 80%;
text-align: center;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
margin-top: 20px;
}
button {
padding: 10px 20px;
background-color: #007aff;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
}
button:disabled {
background-color: #cccccc;
}
.scan-mask {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 500px;
height: calc(100% - 160px);
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
.scan-box {
width: 250px;
height: 250px;
border: 2px solid rgba(0, 255, 0, 0.5);
position: relative;
overflow: hidden;
}
.scan-line {
position: absolute;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(to right, transparent, #00ff00, transparent);
animation: scanLine 3s linear infinite;
}
@keyframes scanLine {
0% { top: 0; }
100% { top: 100%; }
}
</style>
更多推荐


所有评论(0)