用tp框架怎么做网站,python 安装wordpress,WordPress安装在Windows,wordpress follow1. 实现功能
类似扫一扫的功能#xff0c;自动识别到画面中的二维码并进行识别#xff0c;也可以选择从相册中上传。
2. 涉及到的一些插件介绍
vue-qrcode-reader 一组用于检测和解码二维码的Vue.js组件
jsQR 一个纯粹的javascript二维码阅读库#xff0c;该库接收原始…1. 实现功能
类似扫一扫的功能自动识别到画面中的二维码并进行识别也可以选择从相册中上传。
2. 涉及到的一些插件介绍
vue-qrcode-reader 一组用于检测和解码二维码的Vue.js组件
jsQR 一个纯粹的javascript二维码阅读库该库接收原始图像并将定位、提取和解析在其中找到的任何二维码。
zxing-wasm ZXing-C WebAssembly 作为带有类型的 ES/CJS 模块。读/写 web、node、bun 和 deno 中的条形码。
2. vite项目配置本地开发使用https访问
安装basicSsl
pnpm i vitejs/plugin-basic-sslimport { defineConfig } from vite
import vue from vitejs/plugin-vue
import path from path
import basicSsl from vitejs/plugin-basic-ssl// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(), basicSsl()],server: {host: 0.0.0.0,https: true},resolve: {alias: {: path.resolve(__dirname, src)}}
})3. 方式一vue-qrcode-reader实现
npm install vue-qrcode-readervue-qrcode-reader Api 介绍
templatedivqrcode-streamclassqrcode-wrap:torchtorchv-memo[torch]:constraintsselectedConstraints:trackpaintBoundingBoxerroronErrordetectonDetectcamera-ononCameraReadydiv v-ifisSupportTorch classtorch-wrapdiv classtorch click() (torch !torch)div classflash-light v-iftorchMdiFlashlightOff stylewidth: 36px; height: 36px //divdiv classflash-light v-elseMdiFlashlight stylewidth: 36px; height: 36px //div{{ torch ? 关闭闪光灯 : 打开闪光灯 }}/div/divdiv classphoto-wrapdiv classphoto clickhandleOpenFileel-icon size20PictureFilled //el-icon/divdiv classcolor-[#fff]相册/div/div/qrcode-stream/div
/template
script setup langts
// https://gruhn.github.io/vue-qrcode-reader/api/QrcodeStream.html
import { QrcodeStream } from vue-qrcode-reader;
import { PictureFilled } from element-plus/icons-vue;
import MdiFlashlight from ~icons/mdi/flashlight;
import MdiFlashlightOff from ~icons/mdi/flashlight-off;
import { ElMessage } from element-plus;
import { fileOpen } from browser-fs-access;
import _ from lodash;const error ref();
const cameraIsReady ref(false);
const isSupportTorch ref(false); // 是否支持闪光灯
const torch ref(false); // 闪光灯状态
// 相机配置选项: user|environment 默认environment
const selectedConstraints ref({ facingMode: environment });// 检测到二维码后绘制画布类型
function paintBoundingBox(detectedCodes: any, ctx: CanvasRenderingContext2D) {for (const detectedCode of detectedCodes) {const {boundingBox: { x, y, width, height },} detectedCode;ctx.lineWidth 2;ctx.strokeStyle #007bff;// 绘制边框矩形ctx.strokeRect(x, y, width, height);}
}async function onCameraReady(capabilities: any) {// NOTE: on iOS we cant invoke enumerateDevices before the user has given// camera access permission. QrcodeStream internally takes care of// requesting the permissions. The camera-on event should guarantee that this// has happened.try {isSupportTorch.value !!capabilities.torch;cameraIsReady.value true;error.value ;} catch (error) {onError(error);cameraIsReady.value false;}
}
// 错误提示
function onError(err: any) {error.value [${err.name}]: ;if (err.name NotAllowedError) {error.value you need to grant camera access permission;} else if (err.name NotFoundError) {error.value no camera on this device;} else if (err.name NotSupportedError) {error.value secure context required (HTTPS, localhost);} else if (err.name NotReadableError) {error.value is the camera already in use?;} else if (err.name OverconstrainedError) {error.value installed cameras are not suitable;} else if (err.name StreamApiNotSupportedError) {error.value Stream API is not supported in this browser;} else if (err.name InsecureContextError) {error.value Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.;} else {error.value err.message;}ElMessage.warning(error.value);
}
// 用户摄像头的流后
function onDetect(detectedCodes: any) {if (detectedCodes.length 0) {onDecode(detectedCodes[0]?.rawValue);}
}const emit defineEmits([on-success]);// 解码(交给父组件处理进行网络请求)
function onDecode(text: string) {emit(on-success, text);
}
// 文件转成base64
const processFile async (file: any) {let reader new FileReader();reader.readAsDataURL(file);reader.onload (e) {let base64String e.target?.result as string ||;// 此处可对该base64进行获取赋值传入后端, 如果有直接上传文件的接口就可以直接传文件onDecode(base64String)};
};
// 打开图片选择
async function handleOpenFile() {try {const file await fileOpen({ mimeTypes: [image/*] }).catch(() null);if (!file) return;// 计算文件的大小const fileSizeMb _.round(file.size / 1024 / 1024, 2);// 文件大小不能超过 10MBconst limitSizeMb 10;if (fileSizeMb limitSizeMb) {return ElMessage.warning(图片大小限制 ${limitSizeMb}MB);}processFile(file)} catch (error) {console.log([log] - handleOpenUploadIcon - error:, error);}
}
/script
style scoped
.qrcode-wrap {position: fixed !important;top: 0;right: 0;bottom: 0;left: 0;width: 100vw;height: 100vh;z-index: 1 !important;background: rgba(0, 0, 0, 0.5);
}
.torch-wrap {width: 18.75rem;height: 12.5rem;position: fixed !important;left: 50%;top: 50%;transform: translate(-50%, -30%);z-index: 20;
}.torch {position: fixed;bottom: -6.25rem;left: 50%;transform: translateX(-50%);z-index: 20;color: #fff;display: flex;flex-direction: column;align-items: center;
}
.photo-wrap {position: fixed;bottom: 2.875rem;left: 2.875rem;display: flex;flex-direction: column;align-items: center;gap: 6px;
}.photo {height: 3.125rem;width: 3.125rem;background-color: rgba(250, 250, 250, 0.8);border-radius: 50%;display: grid;place-items: center;cursor: pointer;
}
/style
browser-fs-access 这个包需要提前下载
pnpm i browser-fs-access如果需要在离线的环境解析二维码则需要使用zxing-wasm在上面文件的js部分添加以下代码
// 该文件由zxing-wasm项目构建而来
import wasmFile from ./zxing_reader.wasm?url;// !为了离线加载
// https://github.com/gruhn/vue-qrcode-reader/issues/354
setZXingModuleOverrides({locateFile: (path: string, prefix: any) {if (path.endsWith(.wasm)) {return wasmFile;}return prefix path;},
});✨ 该部分完整Demo代码在该文件夹下Demo (二维码实现之vue-qrcode-reader)
4. 方式二jsQR实现
Canvas的基本介绍与使用
templatedivdiv classcanvasBoxdiv classboxdiv classline/divdiv classangle/div/divdiv v-ifisUseTorch classbox2div classtrack clickopenTrackdiv classflash-light v-iftrackStatusMdiFlashlightOff stylewidth: 36px; height: 36px //divdiv classflash-light v-elseMdiFlashlight stylewidth: 36px; height: 36px //div{{ trackStatus ? 关闭闪光灯 : 打开闪光灯 }}/div/divdiv classphoto-wrapdiv classphoto clickhandleClickFileel-icon size20inputclasshide_filereffileReftypefileacceptimage/*;changegetFile/PictureFilled //el-icon/divdiv classcolor-[#fff]相册/div/div/div/div
/templatescript setup langts
// https://github.com/cozmo/jsQR
import jsQR from jsqr;
import { PictureFilled } from element-plus/icons-vue;
import MdiFlashlight from ~icons/mdi/flashlight;
import MdiFlashlightOff from ~icons/mdi/flashlight-off;
import { ElMessage } from element-plus;
import _ from lodash;const props withDefaults(defineProps{// environment 后摄像头 user 前摄像头exact?: environment | user;// whole 全屏 half 半屏size?: whole | half;// 清晰度: fasle 正常 true 高清definition?: boolean;}(),{exact: environment,size: whole,definition: false,}
);
const video ref();
const canvas2d ref();
const canvasWidth ref(520);
const canvasHeight ref(500);
const c ref();
const track ref();
const isUseTorch ref(false);
const trackStatus ref(false);
const fileRef ref();onMounted(() {const windowWidth window.screen.availWidth;const windowHeight window.screen.availHeight;canvasWidth.value windowWidth;canvasHeight.value windowHeight;nextTick(() {video.value document.createElement(video);c.value document.createElement(canvas);c.value.id c;c.value.width canvasWidth.value;c.value.height canvasHeight.value;c.value.style.width 100%;document.querySelector(.canvasBox)?.append(c.value);openScan();});
});onUnmounted(() {closeCamera();
});
// 开始扫描
async function openScan() {try {let width canvasHeight.value;width props.size whole ? width : width * 0.5;width props.definition ? width * 1.6 : width;let height canvasWidth.value;height props.definition ? height * 1.6 : height;const videoParam {audio: false,video: {facingMode: { exact: props.exact }, //强制使用摄像头类型width,height,},};// 获取用户摄像头的视频流const stream await navigator.mediaDevices.getUserMedia(videoParam);if (stream) {video.value.srcObject stream;video.value.setAttribute(playsinline, true); //内联播放video.value.play();requestAnimationFrame(tick);// 返回所有的媒体内容流的轨道列表track.value stream.getVideoTracks()?.[0];setTimeout(() {// 检测摄像头是否支持闪光灯isUseTorch.value track.value.getCapabilities().torch || null;}, 500);}} catch (error) {ElMessage.warning(设备不支持,请检查是否允许摄像头权限);console.log(获取本地设备摄像头---失败, error);}
}
function closeCamera() {if (video.value.srcObject) {video.value.srcObject.getTracks().forEach((track: any) {track.stop();});}
}
function tick() {if (video.value.readyState video.value.HAVE_ENOUGH_DATA) {canvasHeight.value video.value.videoHeight;canvasWidth.value video.value.videoWidth;c.value.width canvasWidth.value;c.value.height canvasHeight.value;if (canvas2d.value undefined) {canvas2d.value c.value.getContext(2d);}canvas2d.value.drawImage(video.value,0,0,canvasWidth.value,canvasHeight.value);const imageData canvas2d.value.getImageData(0,0,canvasWidth.value,canvasHeight.value);// 解析二维码数据const code jsQR(imageData.data, imageData.width, imageData.height, {inversionAttempts: dontInvert,});if (!_.isEmpty(code)) {drawLine(code.location.topLeftCorner,code.location.topRightCorner,#FF3B58);drawLine(code.location.topRightCorner,code.location.bottomRightCorner,#FF3B58);drawLine(code.location.bottomRightCorner,code.location.bottomLeftCorner,#FF3B58);drawLine(code.location.bottomLeftCorner,code.location.topLeftCorner,#FF3B58);if (code.data) {getData(code.data);}}}requestAnimationFrame(tick);
}
function drawLine(begin: any, end: any, color: string) {canvas2d.value.beginPath();canvas2d.value.moveTo(begin.x, begin.y);canvas2d.value.lineTo(end.x, end.y);canvas2d.value.lineWidth 4;canvas2d.value.strokeStyle color;canvas2d.value.stroke();
}
const emit defineEmits([on-success]);function getData(data: string) {emit(on-success, data);closeCamera();
}function openTrack() {trackStatus.value !trackStatus.value;track.value.applyConstraints({advanced: [{ torch: trackStatus.value }],});
}
const handleClickFile () {fileRef.value.click();
};
const getFile (e: any) {const file e.target.files[0];emit(on-success, file);closeCamera();
};
/scriptstyle scoped
.flash-light {display: grid;place-content: center;margin-bottom: 6px;
}.photo-wrap {position: fixed;bottom: 2.875rem;left: 2.875rem;display: flex;flex-direction: column;align-items: center;gap: 6px;
}.photo {height: 3.125rem;width: 3.125rem;background-color: rgba(250, 250, 250, 0.8);border-radius: 50%;display: grid;place-items: center;cursor: pointer;
}.hide_file {display: none;
}page {background-color: #333333;
}.canvasBox {width: 100vw;position: relative;top: 0;bottom: 0;left: 0;right: 0;background-image: linear-gradient(0deg,transparent 24%,rgba(32, 255, 77, 0.1) 25%,rgba(32, 255, 77, 0.1) 26%,transparent 27%,transparent 74%,rgba(32, 255, 77, 0.1) 75%,rgba(32, 255, 77, 0.1) 76%,transparent 77%,transparent),linear-gradient(90deg,transparent 24%,rgba(32, 255, 77, 0.1) 25%,rgba(32, 255, 77, 0.1) 26%,transparent 27%,transparent 74%,rgba(32, 255, 77, 0.1) 75%,rgba(32, 255, 77, 0.1) 76%,transparent 77%,transparent);background-size: 3rem 3rem;background-position: -1rem -1rem;z-index: 10;background-color: #1110;
}.box {width: 11.9375rem;height: 11.9375rem;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -80%);overflow: hidden;border: 0.1rem solid rgba(0, 255, 51, 0.2);z-index: 11;
}.line {height: calc(100% - 2px);width: 100%;background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);border-bottom: 3px solid #00ff33;transform: translateY(-100%);animation: radar-beam 2s infinite alternate;animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);animation-delay: 1.4s;
}.box:after,
.box:before,
.angle:after,
.angle:before {content: ;display: block;position: absolute;width: 3vw;height: 3vw;z-index: 12;border: 0.2rem solid transparent;
}.box:after,
.box:before {top: 0;border-top-color: #00ff33;
}.angle:after,
.angle:before {bottom: 0;border-bottom-color: #00ff33;
}.box:before,
.angle:before {left: 0;border-left-color: #00ff33;
}.box:after,
.angle:after {right: 0;border-right-color: #00ff33;
}keyframes radar-beam {0% {transform: translateY(-100%);}100% {transform: translateY(0);}
}.box2 {width: 18.75rem;height: 12.5rem;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -80%);z-index: 20;
}.track {position: absolute;bottom: -6.25rem;left: 50%;transform: translateX(-50%);z-index: 20;color: #fff;display: flex;flex-direction: column;align-items: center;
}
/style
✨该部分完整Demo代码在该文件夹下Demo (二维码实现之jsQR)
5. 总结
方式一结合vue-qrcode-reader的封装性更强且识别二维码速度更快。 方式二接近了vue-qrcode-reader的底层实现过程。 实际项目开发中更推荐方式一兼容性与稳定性会更好些。 文章转载自: http://www.morning.qxkcx.cn.gov.cn.qxkcx.cn http://www.morning.lstmg.cn.gov.cn.lstmg.cn http://www.morning.xhddb.cn.gov.cn.xhddb.cn http://www.morning.brkc.cn.gov.cn.brkc.cn http://www.morning.kxrhj.cn.gov.cn.kxrhj.cn http://www.morning.qmsbr.cn.gov.cn.qmsbr.cn http://www.morning.ttdxn.cn.gov.cn.ttdxn.cn http://www.morning.djxnn.cn.gov.cn.djxnn.cn http://www.morning.qrlsy.cn.gov.cn.qrlsy.cn http://www.morning.knrgb.cn.gov.cn.knrgb.cn http://www.morning.hxhrg.cn.gov.cn.hxhrg.cn http://www.morning.fdrch.cn.gov.cn.fdrch.cn http://www.morning.wfpmt.cn.gov.cn.wfpmt.cn http://www.morning.ykmg.cn.gov.cn.ykmg.cn http://www.morning.rdkt.cn.gov.cn.rdkt.cn http://www.morning.mbfkt.cn.gov.cn.mbfkt.cn http://www.morning.bgqr.cn.gov.cn.bgqr.cn http://www.morning.wddmr.cn.gov.cn.wddmr.cn http://www.morning.qnwyf.cn.gov.cn.qnwyf.cn http://www.morning.xfxnq.cn.gov.cn.xfxnq.cn http://www.morning.mpflb.cn.gov.cn.mpflb.cn http://www.morning.czlzn.cn.gov.cn.czlzn.cn http://www.morning.tpnxj.cn.gov.cn.tpnxj.cn http://www.morning.ksjmt.cn.gov.cn.ksjmt.cn http://www.morning.khyqt.cn.gov.cn.khyqt.cn http://www.morning.tpchy.cn.gov.cn.tpchy.cn http://www.morning.zxybw.cn.gov.cn.zxybw.cn http://www.morning.qhln.cn.gov.cn.qhln.cn http://www.morning.rjkfj.cn.gov.cn.rjkfj.cn http://www.morning.wmglg.cn.gov.cn.wmglg.cn http://www.morning.ptwqf.cn.gov.cn.ptwqf.cn http://www.morning.rwpjq.cn.gov.cn.rwpjq.cn http://www.morning.syxmx.cn.gov.cn.syxmx.cn http://www.morning.irqlul.cn.gov.cn.irqlul.cn http://www.morning.lgsqy.cn.gov.cn.lgsqy.cn http://www.morning.ysybx.cn.gov.cn.ysybx.cn http://www.morning.yrjym.cn.gov.cn.yrjym.cn http://www.morning.gsjw.cn.gov.cn.gsjw.cn http://www.morning.bmfqg.cn.gov.cn.bmfqg.cn http://www.morning.xjwtq.cn.gov.cn.xjwtq.cn http://www.morning.mrckk.cn.gov.cn.mrckk.cn http://www.morning.rnwt.cn.gov.cn.rnwt.cn http://www.morning.ypbp.cn.gov.cn.ypbp.cn http://www.morning.xmjzn.cn.gov.cn.xmjzn.cn http://www.morning.xdwcg.cn.gov.cn.xdwcg.cn http://www.morning.ysnbq.cn.gov.cn.ysnbq.cn http://www.morning.xsfg.cn.gov.cn.xsfg.cn http://www.morning.qqhersx.com.gov.cn.qqhersx.com http://www.morning.qwmpn.cn.gov.cn.qwmpn.cn http://www.morning.dzgmj.cn.gov.cn.dzgmj.cn http://www.morning.tfei69.cn.gov.cn.tfei69.cn http://www.morning.rjnm.cn.gov.cn.rjnm.cn http://www.morning.xcdph.cn.gov.cn.xcdph.cn http://www.morning.qnzpg.cn.gov.cn.qnzpg.cn http://www.morning.bppml.cn.gov.cn.bppml.cn http://www.morning.kxnjg.cn.gov.cn.kxnjg.cn http://www.morning.dskmq.cn.gov.cn.dskmq.cn http://www.morning.hgbzc.cn.gov.cn.hgbzc.cn http://www.morning.bzgpj.cn.gov.cn.bzgpj.cn http://www.morning.kzrbn.cn.gov.cn.kzrbn.cn http://www.morning.dfrenti.com.gov.cn.dfrenti.com http://www.morning.wlsrd.cn.gov.cn.wlsrd.cn http://www.morning.rfmzc.cn.gov.cn.rfmzc.cn http://www.morning.hhxkl.cn.gov.cn.hhxkl.cn http://www.morning.mhpkz.cn.gov.cn.mhpkz.cn http://www.morning.hhfqk.cn.gov.cn.hhfqk.cn http://www.morning.jnbsx.cn.gov.cn.jnbsx.cn http://www.morning.qzsmz.cn.gov.cn.qzsmz.cn http://www.morning.gqbks.cn.gov.cn.gqbks.cn http://www.morning.yrycb.cn.gov.cn.yrycb.cn http://www.morning.wphzr.cn.gov.cn.wphzr.cn http://www.morning.rlbc.cn.gov.cn.rlbc.cn http://www.morning.rjznm.cn.gov.cn.rjznm.cn http://www.morning.kdgcx.cn.gov.cn.kdgcx.cn http://www.morning.wkcl.cn.gov.cn.wkcl.cn http://www.morning.ktnmg.cn.gov.cn.ktnmg.cn http://www.morning.xlndf.cn.gov.cn.xlndf.cn http://www.morning.wdqhg.cn.gov.cn.wdqhg.cn http://www.morning.tjpmf.cn.gov.cn.tjpmf.cn http://www.morning.tfgkq.cn.gov.cn.tfgkq.cn