uni-app中添加自定义相机(微信小程序+app)
一、微信小程序中
微信小程序中可以直接使用camera标签,这个标签不兼容app,官方文档
<cameradevice-position="back"flash="off":style="{ height: lheight + 'px', width: lwidth + 'px' }"class="w-full"></camera>
拍照方法:
const takePhoto = () => {const ctx = uni.createCameraContext();ctx.takePhoto({quality: "high",success: (res) => {console.log(res.tempImagePath);},});
};
二、uni-app混合开发app中
在app中需要使用live-pusher直播推流组件来实现,官方文档
有两种方法实现,
1、使用live-pusher标签,但是页面需要是nvue平台【推荐使用这种】
2、使用h5plus提供的plus.video.LivePusher来实现,可以使用于vue平台,如果需要在相机上覆盖样式,比如边框之类的比较复杂,实践过后发现获取的图片宽度比相机宽度大,获取快照时间过长,大概需要2秒
1、live-pusher标签
1.1、使用标签形式需要把页面设置为nvue后缀,如果是vue后缀的可以显示相机但是无法使用uni.createLivePusherContext来获取 live-pusher 上下文对象,在拍照的时候无法进入回调函数,所以无法获取拍照的图片
1.2、需要自定义样式可以使用cover-view等来实现
1.3、如果是vue平台添加了一个nvue页面导致运行项目是报警告[plugin:vite:nvue-css],如下:

解决办法:在app.vue引入公共css文件外添加#ifndef APP-PLUS-NVUE条件
// #ifndef APP-PLUS-NVUE
@import "uview-plus/index.scss";
/*每个页面公共css */
@import "colorui/main.css";
//#endif
1.4、在vue3中通过下面获取直播组件的上下文(其他正常把选项式改为组合式):
const content = getCurrentInstance().proxy;
clivePusher.value = uni.createLivePusherContext('livePusher', content);
实例代码vue2写法【仅供参考,根据实际需求修改】:
<template><view style="position: relative;height: 100vh; width:100%;display: flex;flex-direction: column;"><u-navbar :fixed="false" title="拍照" :autoBack="true"></u-navbar><view :style="{height:lheight +'px',width:lwidth+'px'}" class="carema_css"><image v-if="imgsrc" mode="aspectFit" :src="imgsrc" :style="{height:lheight +'px',width:lwidth+'px'}" ></image><live-pusher @statechange="statechange" :style="{height:lheight+'px'}" id='livePusher' ref="livePusher" class="livePusher" url=""mode="FHD" :muted="true" :enable-camera="true" :auto-focus="true" :beauty="1" whiteness="2"aspect="9:16"></live-pusher><cover-view v-if="!imgsrc" class="cover_view" :style="{height:lheight+'px',width:lwidth+'px'}"><cover-view class="cover_css flec-center":style="{width:(lwidth - borderSize.left - borderSize.right - 4)+'px',height:(lheight-borderSize.top-borderSize.bottom -4)+'px',marginTop:borderSize.top+'px',marginLeft:borderSize.left+'px',marginRight:borderSize.right+'px',marginBottom:borderSize.bottom+'px',}"><text class="covertext">请把单据放在边框内拍照{{imgsrc}}</text></cover-view></cover-view></view><view class="btn-css" :style="{width:lwidth+'px'}"><view class="has_imgsrc" :style="{width:lwidth+'px'}" v-if="!imgsrc"><view style="width:52px;"><u-iconname="photo-fill"color="white"size="28"@click="openimage"></u-icon></view><view style="width:52px;"><viewclass="btn-takePhoto"type="primary"@click="snapshot"><u-icon name="camera" color="#067FFF" size="54rpx"></u-icon></view></view><view style="width:52px;"></view></view><view v-else style="padding: 0 66rpx;display: flex;justify-content: space-between;flex-direction: row;"><view@click="snapshotAgainPusher"><text class="comfirmimg_text">重新拍照</text></view><!-- <view@click="cut_img"><text class="comfirmimg_text">裁剪</text></view> --><view><text class="comfirmimg_text" @click="submit">确认上传</text></view></view></view></view>
</template>
<script>import { uploadImg } from "../../config/request.js";export default {data() {return {camerastate: false, //相机准备好了poenCarmeInterval:null,//打开相机的轮询context:null,imgsrc:'',borderSize: {top: null,bottom: null,right: null,left: null,},proportion: null,lheight: null,lwidth: null,navbarHeight: null,border_size_init: 10, // 默认边框宽度}},onLoad(option) {uni.setStorageSync("from_uploadimg_page", true);// W_H_proportion:宽和高的比例值,宽300,高400,传0.75,不传显示默认边框宽度this.proportion = Number(option?.W_H_proportion) || null;this.init_W_h()},onReady() {this.liveInit()},onShow: function () {console.log("App Show");this.snapshotAgainPusher()},onHide: function () {console.log("App Hide");},beforeUnmount() {// 页面退出时销毁scanWinconsole.log("beforeUnmount");this.close();},methods: {cut_img(){uni.navigateTo({url: "/components/customPhotography/imgCut?img="+this.imgsrc,});},liveInit(){// 注意:需要在onReady中 或 onLoad 延时this.context = uni.createLivePusherContext("livePusher", this);this.switchCamera()this.startPreview()},// TODO 后期需要加上ocr识别后才能上传async submit() {const img_code = await this.imgUpload();if (img_code) {uni.$emit("img_upload_img", {img_code,temporary_img: this.imgsrc,});uni.navigateBack(-1);}// uni.$on("img_upload_img", function (data) {});获取图片code},async imgUpload() {uni.showLoading({title: "图片正在上传",mask: true,});const { data, code } = await uploadImg(this.imgsrc);uni.hideLoading();if (code === 200) {return data;} else {return false;}},openimage() {const this_ = this;uni.chooseImage({count: 1,sizeType: ["compressed"], // original 原图,compressed 压缩图,默认二者都有,compressed手机端选照片会压缩图片sizesourceType: ["album"], // album 从相册选图,camera 使用相机,默认二者都有success: function (res) {this_.imgsrc = res.tempFilePaths[0];},fail: function (e) {console.log(e);},complete: function () {},});},init_W_h() {const this_ = this;uni.getSystemInfo({success(res) {this_.navbarHeight = res.model.indexOf("iPhone") !== -1 ? 44 : 48;console.log(res);const canUseHeight =res.screenHeight - res.statusBarHeight - this_.navbarHeight - 86; // 相机总的可用高度const canUseWidth = res.screenWidth; // 相机总的可用宽度const calculatesize = this_.calculateDimensions(// 减去默认的两个边框长度(保证边框不会跟手机边框重叠)canUseWidth - this_.border_size_init * 2,canUseHeight - this_.border_size_init * 2,this_.proportion); // 计算出边框的宽高this_.lheight = canUseHeight;this_.lwidth = canUseWidth;this_.borderSize = {top: (canUseHeight - calculatesize.height) / 2,bottom: (canUseHeight - calculatesize.height) / 2,right: (canUseWidth - calculatesize.width) / 2,left: (canUseWidth - calculatesize.width) / 2,};console.log(canUseHeight);},});},calculateDimensions(maxWidth, maxHeight, aspectRatio) {if (!aspectRatio) {return {width: maxWidth,height: maxHeight,};}// 根据比例计算可能的宽度和高度let possibleWidth = maxWidth;let possibleHeight = maxWidth / aspectRatio;// 检查高度是否超过了最大高度if (possibleHeight > maxHeight) {// 如果超过了,则以最大高度为基准,重新计算宽度possibleHeight = maxHeight;possibleWidth = maxHeight * aspectRatio;}// 返回计算后的宽度和高度return {width: possibleWidth,height: possibleHeight,};},snapshotAgainPusher(){const _this = thisthis.imgsrc = ''this.$nextTick(()=>{_this.context = uni.createLivePusherContext("livePusher", _this);console.log(data.livePusher, "???");_this.startPreview();_this.poenCarme();})},//轮询打开poenCarme(){const _this = this//#ifdef APP-PLUSif (plus.os.name == 'Android') {this.poenCarmeInterval = setInterval(function() {console.log(_this.camerastate);if (!_this.camerastate) _this.startPreview();}, 2500);}//#endif},start: function() {this.context.start({success: (a) => {console.log("livePusher.start:" + JSON.stringify(a));}});},close: function() {this.context.close({success: (a) => {console.log("livePusher.close:" + JSON.stringify(a));}});},snapshot: function() {const this_ = thisthis.context.snapshot({success: (e) => {this_.imgsrc = e.message.tempImagePath}});},stop: function() {this.context.stop({success: (a) => {console.log(JSON.stringify(a));}});},switchCamera: function() {this.context.switchCamera({success: (a) => {console.log("livePusher.switchCamera:" + JSON.stringify(a));}});},startPreview: function() {this.context.startPreview({success: (a) => {console.log("livePusher.startPreview:" + JSON.stringify(a));}});},stopPreview: function() {const _this = thisthis.context.stopPreview({success: (a) => {_this.camerastate = false; //标记相机未启动console.log("livePusher.stopPreview:" + JSON.stringify(a));}});},//状态statechange(e) {const _this = this//状态改变console.log('状态改变',e);if (e.detail.code == 1007) {_this.camerastate = true;} else if (e.detail.code == -1301) {_this.camerastate = false;}},}}
</script>
<style scoped lang="scss">.has_imgsrc{display: flex;flex-direction: row;justify-content: space-around;align-items: center;}.covertext {background: rgba(51, 51, 51, 0.4);color: #f9f9f9;padding: 3px;font-size: 14px;}.flec-center{display: flex;align-items: center;justify-content: center;}.carema_css{// border:3px solid red;position: relative;}.cover_view{width:100%;height: 100%;position: absolute;top: 0px;left: 0px;z-index:99999;box-shadow: inset 0 0 0 2px #000;}.cover_css{text-align: center;color:white;// border:2px solid #fefefe;border-right:1.5px dashed #fefefe;border-top:1.49999px dashed #fefefe;border-bottom:1.49999px dashed #fefefe;border-left:1.5px dashed #fefefe;border-radius: 4px;}
.flex-ctr-full {height: 100vh;display: flex;flex-direction: column;
}
.border-corner {position: absolute;width: 40rpx;height: 40rpx;border-top: 3px solid #fff;border-left: 3px solid #fff;// border-top-left-radius: 14rpx;
}
.borderlt {top: 0px;left: 0px;}
.borderrt {top: 0px;right: 0px;transform: rotate(90deg);}
.borderlb {bottom: 0px;left: 0px;transform: rotate(270deg);}
.borderrb {bottom: 0px;right: 0px;transform: rotate(180deg);}
.covertext {background: rgba(51, 51, 51, 0.4);color: #f9f9f9;padding-left: 5px;font-size: 14px;
}.btn-css {height: 86px;width: 100%;background: rgba(36, 36, 36, 0.75);// padding: 0 66rpx;justify-content: center;
}
.btn-icon {color: #fff;font-size: 56rpx;margin-right: 50rpx;}
.comfirmimg_text {color: #ffffff;font-size: 16px;height:51px;line-height: 51px;;}.btn-takePhoto {z-index: 250;width: 96rpx;height: 96rpx;padding: 22rpx;border-radius: 100%;background-color: #ffffff;// transform: translateY(-50%);box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 12%);}.level-left {display: flex;justify-content: flex-start;
}
.level-right {display: flex;justify-content: flex-end;
}
.level {display: flex;flex-direction: row;justify-content: flex-start;align-items: center;
}
</style>
2、使用plus.video.LivePusher
2.1、这种方法可以在vue页面中使用,自定义样式需要plus.webview.create添加一个html页面来实现,在项目根目录下添加一个hybrid目录,在目录下添加html页面

this.scanWin = plus.webview.create("/hybrid/html/faceTip.html?" + params,"",{top: that.navbarHeight + 44 + "px",background: "transparent",height: that.lheight + "px",width: that.lwidth + "px",});
2.2、拍照获取页面的时候获取的图片是反转的,需要使用plus.zip.compressImage来翻转图片
plus.zip.compressImage({src: imgPath,dst: imgPath,overwrite: true,quality: 40,rotate: 270,},(zipRes) => {//获取到正确的图片}})
2.3、获取的图片宽度会比相机的大,如果有解决办法欢迎分享。
2.4、使用快照snapshot获取图片时间很长,如果有解决办法欢迎分享。
示例【仅供参考,根据实际需求修改】:
相机组件:
<template><view class="flex-ctr-full"><u-navbar :fixed="false" title="拍照" :autoBack="true"></u-navbar><view class="flex-1 relative"><imagev-if="imgsrc"class="select-img w-full h-full"mode="aspectFit":src="imgsrc"></image></view><view class="btn-css"><view class="level h-full"><view v-if="!imgsrc" class="level-left w-65px"><u-iconname="photo-fill"color="white"size="28"@click="openimage"></u-icon></view><viewv-elseclass="level-left w-80px color-white comfirmimg_text":class="!imgsrc ? 'visibility-hidden' : ''"@click="snapshotAgainPusher">重新拍照</view><view:class="imgsrc ? 'visibility-hidden' : ''"class="btn-takePhoto level-item mt-12px"type="primary"@click="takePhoto"><u-icon name="camera" color="#067FFF" size="54rpx"></u-icon></view><view class="level-right" :class="!imgsrc ? 'visibility-hidden' : ''"><text class="comfirmimg_text btn-collection" @click="submit">确认上传</text></view></view></view></view>
</template>
<script>
import { uploadImg } from "../../config/request.js";
export default {data() {return {imgsrc: "",pusher: null,scanWin: null,snapshotTimeoutNumber: 3000,faceInitTimeout: null,snapshTimeout: null,screenHeight: 0,topStatusHeight: 0,borderSize: {top: null,bottom: null,right: null,left: null,},proportion: null,lheight: null,lwidth: null,navbarHeight: null,border_size_init: 20, // 默认边框宽度imgurl: "",};},onLoad(option) {uni.setStorageSync("from_uploadimg_page", true);// W_H_proportion:宽和高的比例值,宽300,高400,传0.75,不传显示默认边框宽度this.proportion = Number(option?.W_H_proportion) || null;this.init_W_h();let that = this;uni.getSystemInfo({success: function (e) {console.log(e);that.screenHeight = e.windowHeight;that.topStatusHeight = e.screenHeight - e.windowHeight + "px";},});//#ifdef APP-PLUSthis.faceInit();//#endif},onHide() {// this.scanWin.close();this.faceInitTimeout && clearTimeout(this.faceInitTimeout);this.snapshTimeout && clearTimeout(this.snapshTimeout);},methods: {openimage() {const this_ = this;uni.chooseImage({count: 1,sizeType: ["compressed"], // original 原图,compressed 压缩图,默认二者都有,compressed手机端选照片会压缩图片sizesourceType: ["album"], // album 从相册选图,camera 使用相机,默认二者都有success: function (res) {this_.imgsrc = res.tempFilePaths[0];this_.imgurl = res.tempFilePaths[0];this_.scanWin.close();this_.pusher.close();},fail: function (e) {console.log(e);},complete: function () {},});},init_W_h() {const this_ = this;uni.getSystemInfo({success(res) {this_.navbarHeight = res.statusBarHeight;console.log(res);const canUseHeight =res.screenHeight - res.statusBarHeight - this_.navbarHeight - 86; // 相机总的可用高度const canUseWidth = res.screenWidth; // 相机总的可用宽度const calculatesize = this_.calculateDimensions(// 减去默认的两个边框长度(保证边框不会跟手机边框重叠)canUseWidth - this_.border_size_init * 2,canUseHeight - this_.border_size_init * 2,this_.proportion); // 计算出边框的宽高this_.lheight = canUseHeight;this_.lwidth = canUseWidth;this_.borderSize = {top: (canUseHeight - calculatesize.height) / 2,bottom: (canUseHeight - calculatesize.height) / 2,right: (canUseWidth - calculatesize.width) / 2,left: (canUseWidth - calculatesize.width) / 2,};},});},calculateDimensions(maxWidth, maxHeight, aspectRatio) {if (!aspectRatio) {return {width: maxWidth,height: maxHeight,};}// 根据比例计算可能的宽度和高度let possibleWidth = maxWidth;let possibleHeight = maxWidth / aspectRatio;// 检查高度是否超过了最大高度if (possibleHeight > maxHeight) {// 如果超过了,则以最大高度为基准,重新计算宽度possibleHeight = maxHeight;possibleWidth = maxHeight * aspectRatio;}// 返回计算后的宽度和高度return {width: possibleWidth,height: possibleHeight,};},faceInit() {let that = this;uni.showLoading({title: "加载中",mask: true,});this.faceInitTimeout = setTimeout(() => {this.pusherInit();const params = `height=${that.lheight}&width=${that.lwidth}&top=${this.borderSize.top}&left=${this.borderSize.left}&right=${this.borderSize.right}&bottom=${this.borderSize.bottom}`;this.scanWin = plus.webview.create("/hybrid/html/faceTip.html?" + params,"",{top: that.navbarHeight + 44 + "px",background: "transparent",height: that.lheight + "px",width: that.lwidth + "px",});setTimeout(() => {this.scanWin.show();}, 200);}, 200);uni.hideLoading();},pusherInit() {let that = this;const pages = getCurrentPages(); // 获取当前页面栈const page = pages[pages.length - 1]; // 获取当前页面的对象const currentWebview = page.$getAppWebview();console.log(that.screenHeight - 50 + "px",that.lheight + "px",that.navbarHeight,that.topStatusHeight);this.pusher = plus.video.createLivePusher("livepusher", {url: "",top: that.navbarHeight + 44 + "px",left: "0px",width: that.lwhite + "px",height: that.lheight + "px",position: "absolute",aspect: "3:4","z-index": 999,});currentWebview.append(this.pusher);// this.pusher.switchCamera(); //换为前置摄像头this.pusher.preview();uni.hideLoading();},//拍照takePhoto() {let that = this;uni.showLoading({title: "照片生成中",mask: true,});// this.snapshTimeout = setTimeout(() => {console.log(this.pusher);this.pusher.snapshot((res) => {console.log("走到这啦2", res);const src = res.tempImagePath;that.imgurl = res.tempImagePath;that.getImage(src);},(err) => {console.log("拍照失败", err);uni.showToast({title: "拍照失败",});});// }, 3000);},// 重拍snapshotAgainPusher() {this.faceInit(); //全部重新加载this.imgsrc = "";},getImage(imgPath) {let that = this;plus.zip.compressImage({src: imgPath,dst: imgPath,overwrite: true,quality: 40,rotate: 270,},(zipRes) => {that.imgsrc = zipRes.target;that.scanWin.close();uni.hideLoading();uni.showToast({title: "照片已生成",duration: 1000,success() {},});that.pusher.close();},function (error) {uni.showToast({title: "照片生成失败",});});},// TODO 后期需要加上ocr识别后才能上传async submit() {const img_code = await this.imgUpload();if (img_code) {uni.$emit("img_upload_img", {img_code,temporary_img: this.imgurl,});uni.navigateBack(-1);}// uni.$on("img_upload_img", function (data) {});获取图片code},async imgUpload() {uni.showLoading({title: "图片正在上传",mask: true,});const { data, code } = await uploadImg(this.imgurl);uni.hideLoading();console.log(data, code);if (code === 200) {return data;} else {return false;}},},beforeUnmount() {// 页面退出时销毁scanWinconsole.log("beforeUnmount");this.scanWin.close();},
};
</script><style scoped lang="scss">
.cover {position: absolute;z-index: 200;top: 0;left: 0;right: 0;bottom: 0;
}
.flex-ctr-full {height: 100vh;display: flex;flex-direction: column;
}
.border-corner {position: absolute;width: 40rpx;height: 40rpx;border-top: 3px solid #fff;border-left: 3px solid #fff;// border-top-left-radius: 14rpx;&.borderlt {top: 0px;left: 0px;}&.borderrt {top: 0px;right: 0px;transform: rotate(90deg);}&.borderlb {bottom: 0px;left: 0px;transform: rotate(270deg);}&.borderrb {bottom: 0px;right: 0px;transform: rotate(180deg);}
}.covertext {background: rgba(51, 51, 51, 0.4);color: #f9f9f9;padding-left: 5px;font-size: 14px;
}.btn-css {height: 86px;line-height: 86px;width: 100%;background: rgba(36, 36, 36, 0.75);padding: 0 66rpx;.btn-icon {color: #fff;font-size: 56rpx;margin-right: 50rpx;&.btn-collection {margin-left: 50rpx;margin-right: 0;}}.comfirmimg_text {padding: 14rpx;color: #f9f9f9;font-size: 16px;}.btn-takePhoto {z-index: 250;width: 96rpx;height: 96rpx;padding: 22rpx;border-radius: 100%;background-color: #ffffff;// transform: translateY(-50%);box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 12%);}.level-left,.level-right {flex-basis: auto;flex-grow: 0;flex-shrink: 0;display: flex;}
}
.level-left {justify-content: flex-start;
}
.level-right {justify-content: flex-end;
}
.level {display: flex;justify-content: space-between;
}
</style>
自定义样式的覆盖文件faceTip.html:
头部需要添加页面根据设备进行缩放
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"><title></title><script>function getURLParameter(name) {// 使用window.location.search获取URL中的查询字符串var query = window.location.search.substring(1);// 使用new URLSearchParams创建一个查询字符串参数的实例var vars = query.split("&");for (var i = 0; i < vars.length; i++) {var pair = vars[i].split("=");if (pair[0] == name) {return pair[1];}}return (false);}// 调用函数获取特定参数// var paramsValue = {}// paramsValue.top = getURLParameter('top');<style>.facecontent {height: 100%;position: absolute;width: 100%;text-align: center;}.cover {height: calc(100% - 100px);width: calc(100% - 100px);text-align: center;padding: 40px;display: flex;justify-content: center;align-items: center;border: 3px dashed #f9f9f9;border-radius: 20px;}.covertext {background: rgba(51, 51, 51, 0.4);color: #f9f9f9;font-size: 15px;padding: 4px;}</style></head><body><div class="facecontent" id="facecontent_id"><div class="cover" id="cover_border"><div class="covertext">请把单据放在边框内拍照</div></div></div></body>
</html>
相关文章:
uni-app中添加自定义相机(微信小程序+app)
一、微信小程序中 微信小程序中可以直接使用camera标签,这个标签不兼容app,官方文档 <cameradevice-position"back"flash"off":style"{ height: lheight px, width: lwidth px }"class"w-full"></c…...
Android中的SSL/TLS加密及其作用
Android中的SSL/TLS加密及其作用 SSL/TLS(Secure Sockets Layer/Transport Layer Security)加密技术是保护网络通信安全的关键技术之一,广泛应用于各种网络通信场景,包括Android应用开发。在Android中,SSL/TLS加密技术…...
东芝TLP176AM光耦合器:提升设计性能的关键元件
在当今快速发展的电子领域,精确性、可靠性和效率比以往任何时候都更加重要。作为工程师,我们不断寻找不仅能满足严格技术要求,还能提升整体设计性能的元件。其中,东芝的TLP176AM光耦合器正因其卓越的性能在业界备受关注。 什么是…...
MySQL数据库:基础介绍下载与安装
数据库基础知识先谈发音MySQL如何发音?在国内MySQL发音有很多种,Oracle官方文档说他们念作My sequal[si:kwəl]。 数据库基本概念 1。数据数据(Data)是指对客观事物进行描述并可以鉴别的符号,这些符号是可识别的、抽…...
原理代码解读:基于DiT结构视频生成模型的ControlNet
Diffusion Models视频生成-博客汇总 前言:相比于基于UNet结构的视频生成模型,DiT结构的模型最大的劣势在于生态不够完善,配套的ControlNet、IP-Adapter等开源权重不多,导致难以落地。最近DiT-based 5B的ControlNet开源了,相比于传统的ControlNet有不少改进点,这篇博客将从…...
【Pip】初识 Pip:Python 包管理的基本命令详解
目录 引言1. 什么是 pip?1.1 pip 的安装 2. pip 的基本命令2.1 pip install2.2 pip uninstall2.3 pip list2.4 pip show2.5 pip freeze2.6 pip search2.7 pip install -U2.8 pip install -r2.9 pip check2.10 pip cache 3. 使用示例3.1 安装多个包3.2 创建虚拟环境3…...
JMeter 中两大高级线程组的区别与应用
一、JMeter 中的高级线程组概述 最近群里的测试小伙伴在问在 JMeter 中,“jpgc - Ultimate Thread Group”和“jpgc - Stepping Thread Group 阶梯加压”有哪些区别和实际应用场景有哪些?所以这里也跟大家分享一下 JMeter 作为一款强大的性能测试工具&a…...
深入理解伪元素与伪类元素
在“探秘盒子浮动,破解高度塌陷与文字环绕难题,清除浮动成关键!”中,我们讲到如果父盒由于各种原因未设置高度, 子盒的浮动会导致父盒的高度塌陷。为了解决高度塌陷的问题,我们可以添加伪元素。 一、伪元素…...
HDU Romantic
题目大意:现在告诉你两个非负整数 a 和 b。找到满足 X*a Y*b 1 的非负整数 X 和整数 Y。如果没有这样的答案,请写 “sorry”。 思路:这是一道扩展欧几里得模板题,唯一容易错的就是 x 有可能是负数,要把它改成非负数…...
[每日一练]通过shift移动函数实现连续数据的需求
该题目来源于力扣: 603. 连续空余座位 - 力扣(LeetCode) 题目要求: 表: Cinema------------------- | Column Name | Type | ------------------- | seat_id | int | | free | bool | ------------------- Seat_id…...
go 中的斐波那契数实现以及效率比较
package mainimport ("fmt""math/big""time" )// FibonacciRecursive 使用递归方法计算斐波那契数列的第n个数 func FibonacciRecursive(n int) *big.Int {if n < 1 {return big.NewInt(int64(n))}return new(big.Int).Add(FibonacciRecursiv…...
基于ASP.NET的小型超市商品管理系统
文章目录 前言项目介绍技术介绍功能介绍核心代码数据库参考 系统效果图 前言 示 文章底部名片,获取项目的完整演示视频,免费解答技术疑问 项目介绍 小型超市商品管理系统是一款针对小型超市日常运营需求设计的软件解决方案。该系统主要内容有商品类别…...
spdlog学习记录
spdlog Loggers:是 Spdlog 最基本的组件,负责记录日志消息。在 Spdlog 中,一个 Logger 对象代表着一个日志记录器,应用程序可以使用 Logger 对象记录不同级别的日志消息Sinks:决定了日志消息的输出位置。在 Spdlog 中&…...
linux替换某个文件的某段内容命令
假设文件是a.sql 里面的库是abc,我想把这个abc给替换掉,改成hahaha cat a.sql |grep abc|sed -i s/abc/hahaha/g a.sql 如果想写个脚本指定整个文件夹中的内容替换 #!/bin/bash # 检查是否提供了文件夹路径 if [ -z "\$1" ]; then echo &…...
什么是SQL注入攻击?如何防止呢?
目录 一、什么是SQL注入? 二、如何防止? 2.1 使用预编译语句 2.2 使用 ORM 框架 2.3 用户输入校验 一、什么是SQL注入? SQL 注入是一种常见的网络安全漏洞,攻击者通过在应用程序的用户输入中插入恶意的 SQL 代码ÿ…...
consumer 角度讲一下i2c外设
往期内容 I2C子系统专栏: I2C(IIC)协议讲解-CSDN博客SMBus 协议详解-CSDN博客I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客内核提供的通用I2C设备驱动I2c-dev.c分析:注册篇内核提供的通用I2C设备驱动I2C-dev.…...
面试经典150题刷题记录
数组部分 1. 合并两个有序的子数组 —— 倒序双指针避免覆盖 88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使…...
【HarmonyOS NEXT】实现保存base64图片到图库
上篇文章介绍了HarmonyOS NEXT如何保存base64文件到download目录下,本次介绍如何保存base64图片到图库,网络图片保存方式大同小异,先下载图片,然后再保存 phAccessHelper.showAssetsCreationDialog参考官方文档’ ohos.file.pho…...
开题答辩最怕被问什么?教你用ChatGPT轻松准备,稳拿高分!
AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 开题答辩是学位论文写作过程中的重要环节,能帮助导师评估你的研究计划是否可行,并对后续写作起到指导作用。很多同学在面对导师提问时会感到紧张,因此提前准备好常见问题的…...
Unity3D功耗和发热分析与优化详解
前言 Unity3D作为广泛使用的游戏开发引擎,在游戏开发过程中,功耗和发热问题一直是开发者需要重点关注的问题。功耗和发热不仅影响用户体验,还可能对设备的硬件寿命造成一定影响。本文将从技术角度详细分析Unity3D游戏在移动设备上的功耗和发…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
