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游戏在移动设备上的功耗和发…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

CSS 工具对比:UnoCSS vs Tailwind CSS,谁是你的菜?
在现代前端开发中,Utility-First (功能优先) CSS 框架已经成为主流。其中,Tailwind CSS 无疑是市场的领导者和标杆。然而,一个名为 UnoCSS 的新星正以其惊人的性能和极致的灵活性迅速崛起。 这篇文章将深入探讨这两款工具的核心理念、技术差…...

Python基于蒙特卡罗方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融投资中,风险管理是确保资产安全和实现稳健收益的关键环节。随着市场波动性的增加,传统…...

基于规则的自然语言处理
基于规则的自然语言处理 规则方法形态还原(针对英语、德语、法语等)中文分词切分歧义分词方法歧义字段消歧方法分词带来的问题 词性标注命名实体分类机器翻译规则方法的问题 规则方法 以规则形式表示语言知识,强调人对语言知识的理性整理&am…...