扫码方式:使用Html5Qrcode库
1.npm install html5-qrcode
2.import { Html5Qrcode } from "html5-qrcode"; // 引入 H5 扫码库
3-1相机扫码的vue弹窗代码
<u-overlay :show="scanShow" @click="scanShow = false" opacity="0.6">
<view class="warp">
<view class="rect">
<view id="sreader" class="sreader" style="width: 100%; height: 100%">
</view>
</view>
<div class="scan-wave" :class="{ active: cameraReady }"></div>
<view class="btn">
<u-button
color="#AB004F"
type="primary"
class="next-btn"
@click="stopScan"
>停止扫码</u-button
>
</view>
</view>
</u-overlay>
3-2选择图片扫码
<view id="reader" class="reader" style="display: none"></view>
4.点击按钮选择扫码方式
chooseScanWay() {
uni.showActionSheet({
itemList: ["相机扫码", "选择图片扫码"],
success: (res) => {
if (res.tapIndex === 0) {
console.log("1");
this.scanShow = true;
this.scan();
} else if (res.tapIndex === 1) {
console.log(2);
this.h5AlbumScan();
}
},
fail: (err) => {
console.log("取消选择:", err);
},
});
},
5-1 选择图片扫码
h5AlbumScan() {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.style.display = "none";
fileInput.onchange = (e) => {
const file = e.target.files[0];
if (!file) return;
const htmlCode = new Html5Qrcode("reader");
htmlCode
.scanFile(file)
.then((decodedText) => {
console.log(decodedText, "decodedText");
uni.showToast({ title: "扫码成功" + decodedText, icon: "success" });
})
.catch((err) => {
uni.showToast({ title: "图片中未识别到二维码", icon: "none" });
console.error("图片解码失败", err);
});
document.body.removeChild(fileInput);
};
document.body.appendChild(fileInput);
fileInput.click();
},
5-2 相机扫码方法
scan() {
const containerRpx = 500;
const pxPerRpx = window.innerWidth / 750;
const containerPx = containerRpx * pxPerRpx;
const height = window.innerHeight;
const width = window.innerWidth;
const codeContent = "1024";
Html5Qrcode.getCameras()
.then((devices) => {
this.html5QrCode = new Html5Qrcode("sreader");
const aspectRatio = height / width;
if (devices && devices.length) {
setTimeout(() => {
this.cameraReady = true;
}, 0);
this.html5QrCode
.start(
{ facingMode: { exact: "environment" } },
{
fps: 10,
aspectRatio: aspectRatio,
qrbox: {
width: width * 1,
height: height * 1,
},
videoConstraints: {
facingMode: "environment",
aspectRatio: aspectRatio,
},
disableAutoFocus: true,
tryHarder: true,
},
(decodedText, decodedResult) => {
console.log("decodedText", decodedText);
uni.showToast({
title: decodedText,
icon: "none",
});
},
(errorMessage) => {
},
)
.catch((err) => {
console.log("Start failed, handle it.");
});
}
})
.catch((err) => {
console.log(err);
uni.showToast({
title: err,
icon: "none",
});
});
},
6.扫码完成需要关闭摄像头
stopScan() {
if (this.html5QrCode) {
this.html5QrCode
.stop()
.then(() => {
console.log("摄像头已关闭");
this.scanShow = false;
this.html5QrCode = null;
})
.catch((err) => {
console.error("关闭摄像头失败", err);
});
} else {
this.scanShow = false;
}
},
7.扫码模块样式
.warp {
display: flex;
align-items: center;
// justify-content: center;
// padding-top: 50%;
height: 100vh;
flex-direction: column;
}
.btn {
// padding-top: 100rpx;
position: absolute;
bottom: 100rpx;
}
.rect {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
// background-color: #fff;
// background:
//
// linear-gradient(#007aff, #007aff) 0 0 / 40rpx 10rpx no-repeat,
// linear-gradient(#007aff, #007aff) 0 0 / 10rpx 40rpx no-repeat,
//
// linear-gradient(#007aff, #007aff) 100% 0 / 40rpx 10rpx no-repeat,
// linear-gradient(#007aff, #007aff) 100% 0 / 10rpx 40rpx no-repeat,
//
// linear-gradient(#007aff, #007aff) 0 100% / 40rpx 10rpx no-repeat,
// linear-gradient(#007aff, #007aff) 0 100% / 10rpx 40rpx no-repeat,
//
// linear-gradient(#007aff, #007aff) 100% 100% / 40rpx 10rpx no-repeat,
// linear-gradient(#007aff, #007aff) 100% 100% / 10rpx 40rpx no-repeat;
// background-color: #fff;
background-color: transparent;
.sreader {
position: absolute;
}
}
.scan-wave {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1rpx;
// will-change: transform;
// backface-visibility: hidden;
transform: translateZ(0);
background: linear-gradient(
90deg,
transparent,
#07c160,
#07c160,
transparent
);
border-radius: 50%;
box-shadow: 0 0 30rpx 10rpx rgba(7, 193, 96, 0.3);
pointer-events: none;
z-index: 2;
animation: scanMove 3s linear infinite;
animation-play-state: paused;
}
.scan-wave.active {
animation-play-state: running;
}
@keyframes scanMove {
0% {
top: 0;
opacity: 1;
}
85% {
top: 85%;
opacity: 1;
}
100% {
top: 100%;
opacity: 1;
}
}