vue实现h5扫码
插件 html5-qrcode npm 地址
html5-qrcode 是一个基于 JavaScript 轻量级和跨平台的扫码插件。允许用户使用摄像头扫描二维码,并且解析为文本或者 url。
- 支持扫描不同类型的二维码和条形码
- 支持不同的平台,Android、IOS、Windows、MacOs 或者 linux
- 支持不同的浏览器,Chrome、Safari、Edge 等
- 支持扫描本地文件
访问摄像头涉及用户隐私,所以访问环境必须在https下
实现(该代码环境基于 vue3)
-
安装依赖
npm install html5-qrcode
-
引入
import { Html5Qrcode } from "html5-qrcode";
-
使用
-
setup 数据
const state = reactive({ html5QrCode: null, fileList: [], });
-
判断当前环境下是否有摄像头
Html5Qrcode.getCameras() .then((devices) => { if (devices && devices.length) { // 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个 state.html5QrCode = new Html5Qrcode("reader"); // reader 放置扫码功能的元素ID startInit(); } }) .catch(() => { // 摄像头无访问权限 });
-
扫码
const startInit = () => { state.html5QrCode .start( // environment后置摄像头 user前置摄像头 { facingMode: "environment" }, { fps: 1, // 可选,每n秒帧扫描一次 qrbox: { width: 250, height: 250, }, // 扫描的 UI框 }, (decodedText, decodedResult) => { // 扫描结果 } ) .catch((err) => { // 扫码错误信息 let message = ""; if (typeof err == "string") { message = "识别失败"; } else { if (err.name == "NotAllowedError") { message = "您需要授予相机访问权限!"; } if (err.name == "NotFoundError") { message = "这个设备上没有摄像头!"; } if (err.name == "NotSupportedError") { message = "摄像头访问只支持在安全的上下文中,如https或localhost!"; } if (err.name == "NotReadableError") { message = "相机被占用!"; } if (err.name == "OverconstrainedError") { message = "安装摄像头不合适!"; } if (err.name == "StreamApiNotSupportedError") { message = "此浏览器不支持流API!"; } } }); };
-
-
停止扫码
const stop = () => { state.html5QrCode .stop() .then((ignore) => { console.log("停止扫码", ignore); }) .catch((err) => { console.log(err); showToast("停止扫码失败"); }); };
-
识别本地文件
const dealSelectFiles = () => { try { window.qrcode.callback = (result) => { // 识别成功 }; // get select files. let file = state.fileList[0].file; var reader = new FileReader(); reader.onload = (function () { return function (e) { window.qrcode.decode(e.target.result); }; })(file); reader.readAsDataURL(file); } catch (error) { // 识别失败 } };
-
在离开页面时要停止扫码功能
onUnmounted(() => { //扫描设备是否在运行 if (state.html5QrCode.isScanning) { stop(); } });
完整代码
<template>
<div class="scanCode">
<div class="container">
<div class="qrcode">
<div id="reader"></div>
</div>
</div>
<div class="btn">
<div class="left-back">
<van-icon name="arrow-left" @click="clickBack" />
</div>
<div class="right-file">
<van-uploader
v-model="fileList"
:preview-image="false"
:after-read="dealSelectFiles"
>
<van-icon name="photo-o"
/></van-uploader>
</div>
</div>
</div>
</template>
<script>
import { reactive } from "vue";
import { defineComponent, toRefs, onMounted, onUnmounted } from "vue";
import { Html5Qrcode } from "html5-qrcode";
import { showToast } from "vant";
export default defineComponent({
setup() {
const state = reactive({
html5QrCode: null,
fileList: [],
});
const start = () => {
state.html5QrCode
.start(
{ facingMode: "environment" },
{
fps: 1,
qrbox: { width: 250, height: 250 },
},
(decodedText, decodedResult) => {
console.log("decodedText", decodedText);
console.log("decodedResult", decodedResult);
}
)
.catch((err) => {
console.log("扫码错误信息", err);
let message = ""; // 错误信息处理仅供参考,具体描述自定义
if (typeof err == "string") {
message = "二维码识别失败!";
} else {
if (err.name == "NotAllowedError") {
message = "您需要授予相机访问权限!";
}
if (err.name == "NotFoundError") {
message = "这个设备上没有摄像头!";
}
if (err.name == "NotSupportedError") {
message =
"摄像头访问只支持在安全的上下文中,如https或localhost!";
}
if (err.name == "NotReadableError") {
message = "相机被占用!";
}
if (err.name == "OverconstrainedError") {
message = "安装摄像头不合适!";
}
if (err.name == "StreamApiNotSupportedError") {
message = "此浏览器不支持流API!";
}
}
});
};
const getCameras = () => {
Html5Qrcode.getCameras()
.then((devices) => {
if (devices && devices.length) {
state.html5QrCode = new Html5Qrcode("reader");
start();
}
})
.catch((err) => {
showToast({
message: "摄像头无访问权限!",
duration: 3000,
});
});
};
const stop = () => {
state.html5QrCode
.stop()
.then((ignore) => {
console.log("停止扫码", ignore);
})
.catch((err) => {
console.log(err);
showToast("停止扫码失败");
});
};
const dealSelectFiles = () => {
try {
window.qrcode.callback = (result) => {
showToast("成功了,结果是:" + result);
}; // get select files.
let file = state.fileList[0].file;
var reader = new FileReader();
reader.onload = (function () {
return function (e) {
window.qrcode.decode(e.target.result);
};
})(file);
reader.readAsDataURL(file);
} catch (error) {
showToast({
message: "图片识别失败!",
duration: 3000,
});
}
};
onMounted(() => {
getCameras();
});
onUnmounted(() => {
//扫描设备是否在运行
if (state.html5QrCode.isScanning) {
stop();
}
});
return {
...toRefs(state),
getCameras,
dealSelectFiles,
};
},
});
</script>
<style lang="scss" scoped>
.scanCode {
height: 100vh;
display: flex;
flex-direction: column;
background: rgba(0, 0, 0);
}
.container {
height: 90vh;
position: relative;
width: 100%;
}
.qrcode {
height: 100%;
}
#reader {
top: 50%;
left: 0;
transform: translateY(-50%);
}
.btn {
flex: 1;
padding: 3vw;
display: flex;
justify-content: space-around;
color: #fff;
font-size: 8vw;
align-items: flex-start;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南