集群网站建设,网站建设必备条件,游戏推广赚佣金,域名批量查询系统前言#xff1a; 最近在使用uniapp开发微信小程序#xff0c;遇到这样一个需求#xff0c;用户想要连续拍照#xff0c;拍完之后可以删除照片#xff0c;保留自己想要的照片#xff0c;然后上传到服务器上。由于原生的方法只能一个个拍照上传#xff0c;所以只能自己通过…前言 最近在使用uniapp开发微信小程序遇到这样一个需求用户想要连续拍照拍完之后可以删除照片保留自己想要的照片然后上传到服务器上。由于原生的方法只能一个个拍照上传所以只能自己通过视频流截取帧的方式开发一个拍照功能组件交互和界面都是自己开发供项目其他需要的地方使用。现做下记录以下是完整代码
// Camera.vue 页面子组件
templateview v-ifshowCamera classpage-body!--图片预览--!-- template v-ifpreviewSrcimage clickhandleBack src../../static/images/common/back.png classclose-icon/imageimage :srcpreviewSrc classpreview-img/image/template --!--图片上传--image clickhandleCancel src../../static/images/common/close.png classclose-icon/image!--摄像头组件--cameradevice-positionbackflashoffrefcameraclasspage-camera/camera!--拍照--image clicktakePhoto src../../static/images/common/photo.png classphoto/image!--选择的图片--view classselect-phototemplate v-ifimageList?.length 0view classstorageview v-for(item, index) in imageList :keyindex styleposition: relative;image :srcitem.tempImagePath classselect-img clickhandlePreviewImg(item)/imageimage clickhandleDelete(index) src../../static/images/common/cross.png classback-icon/image/view/view/templateview classfinish clickhandleFinish确认/view/view!--添加水印--view styleposition: absolute; top: -999999px;canvas stylewidth: 60px; height: 60px iduploadCanvas canvas-iduploadCanvas/canvas/view/view
/templatescript setup nameMyCameraimport { ref, onMounted, getCurrentInstance } from vueimport { getToken } from /utils/auth.jsimport { useUserStore, useHomeStore } from /store/index.jsimport { $showToast, validateNull, timestampToDateTime } from /utils/index.jsconst userStore useUserStore()const homeStore useHomeStore()const props defineProps({showCamera: {type: Boolean,default: false},photos: {type: Array,default: []}})const { proxy } getCurrentInstance()const imageList ref([]) // 选择图片const uploadFileArr ref([]) // 已上传的图片const previewSrc ref() // 图片预览const $emit defineEmits([handleCancel, handleFinish])onMounted(() {imageList.value []uploadFileArr.value []})// 添加水印const waterMarkerOperate (filePath) {const address 江苏省xxxxxuni.getImageInfo({src: filePath,success: ress {let ctx uni.createCanvasContext(uploadCanvas, proxy);// 将图片绘制到canvas内 60-宽, 60-高const cWidth 40;const cHeight 60;ctx.drawImage(filePath, 0, 0, 60, cHeight);const fontSize 2;ctx.setFillStyle(rgba(128, 128, 128, 0.9)); // 设置背景色ctx.fillRect(0, 65, cWidth, 34); // 设置背景位置ctx.setFontSize(fontSize); // 设置字体大小ctx.setFillStyle(#FFFFFF); // 设置字体颜色const lineHeight 2; // 行高设置let textToWidth (ress.width / 3) * 0.01; // 绘制文本的左下角x坐标位置let textToHeight (ress.height / 3) * 0.1; // 绘制文本的左下角y坐标位置const nowTime timestampToDateTime(); // 当前日期ctx.fillText(日 期${nowTime}, textToWidth, textToHeight);textToHeight lineHeight;const lines [];let line ;// 遍历字符并拆分行for (const char of address) {const testLine line char;const testWidth ctx.measureText(testLine).width;if (testWidth 24) {lines.push(line);line char;} else {line testLine;}}// 加入最后一行lines.push(line);const addressLabel 地 址;for (let i 0; i lines.length; i) {const textLine lines[i];// 仅在第一行添加地址标签const lineText i 0 ? addressLabel textLine : textLine;ctx.fillText(lineText, textToWidth, textToHeight);textToHeight lineHeight;}// 绘制完成后在下一个事件循环将 canvas 内容导出为临时图片地址ctx.draw(false, (() {setTimeout(() {uni.canvasToTempFilePath({canvasId: uploadCanvas,success: res1 {// 生成水印imageList.value.push({tempImagePath: res1.tempFilePath})},fail: error {console.log(错误, error);},}, proxy);}, 500);})())}});}// 拍照const takePhoto () {// 最多拍摄6张const totalImages (imageList.value?.length || 0) (props.photos?.length || 0);if (totalImages 5) {$showToast(已达拍照上限)return}uni.createCameraContext().takePhoto({quality: high,success: (res) {waterMarkerOperate(res.tempImagePath)}})}// 拍照完成const handleFinish async () {// 调用上传接口const uploadPromises imageList.value?.map(item {return new Promise((resolve, reject) {uni.uploadFile({url: config.baseUrl /uploadUrl,filePath: item?.tempImagePath,name: file,header: {Authorization: Bearer getToken()},success: (res) {try {const data JSON.parse(res.data)if (data.fileName) {resolve(data.fileName)}} catch (e) {reject(e)}}})})})const imgList await Promise.all(uploadPromises);imgList.forEach(img {uploadFileArr.value.push(img)})$emit(handleFinish, JSON.stringify({uploadFileArr: uploadFileArr.value}))$showToast(上传成功)imageList.value []uploadFileArr.value []}// 图片预览const handlePreviewImg (item) {previewSrc.value item?.tempImagePath}// 返回const handleBack () {previewSrc.value }// 关闭const handleCancel () {imageList.value []uploadFileArr.value []$emit(handleCancel)}// 删除图片未上传const handleDelete (index) {imageList.value.splice(index, 1)}
/scriptstyle langscss
.page-body {width: 100%;height: 100%;position: fixed;top: 0;left: 0;z-index: 99;background: rgba(0, 0, 0, 0.6);display: flex;justify-content: center;align-items: center;.close-icon {position: absolute;left: 30rpx;top: 100rpx;width: 44rpx;height: 44rpx;z-index: 99;}.page-camera {width: 100%;height: 90%;position: absolute;top: 0;}.photo {width: 140rpx;height: 140rpx;position: absolute;bottom: 256rpx;}.select-photo {width: 100%;height: 180rpx;display: flex;flex-direction: row;align-items: center;margin-bottom: 12rpx;background: #000;position: absolute;bottom: 0;.storage {max-width: 540rpx; overflow-x: auto;display: flex;flex-direction: row;}.finish {width: 120rpx;height: 60rpx;line-height: 60rpx;font-size: 28rpx;color: #fff;text-align: center;position: absolute;right: 37rpx;background: #0fad70;border-radius: 10rpx;}.select-img {width: 120rpx;height: 120rpx;margin-right: 16rpx;border-radius: 10rpx;}.back-icon {width: 30rpx;height: 30rpx;position: absolute;right: 0;top: -10rpx;}}.preview-img {width: 100%;height: auto;object-fit: contain;}
}
/style// 时间戳转成时间
const timestampToDateTime (timestamp) {const date timestamp ? new Date(timestamp) : /* __PURE__ */ new Date();const year date.getFullYear();const month String(date.getMonth() 1).padStart(2, 0);const day String(date.getDate()).padStart(2, 0);const hours String(date.getHours()).padStart(2, 0);const minutes String(date.getMinutes()).padStart(2, 0);const seconds String(date.getSeconds()).padStart(2, 0);return ${year}-${month}-${day} ${hours}:${minutes}:${seconds};
};// 父组件使用
// index.vue
import Camera from /components/Camera.vuemy-camera refcameraRef showCameratrue :photosform.photo handleFinishhandleFinish handleCancelhandleCancel/my-camerascript setupconst handleFinish () {// 上传图片完成的逻辑处理}const handleCancel () {// 上传图片取消的逻辑处理}
/script欢迎各位大佬有意见的话评论区留言互相交流学习~ 文章转载自: http://www.morning.lxlzm.cn.gov.cn.lxlzm.cn http://www.morning.bwgrd.cn.gov.cn.bwgrd.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.kncrc.cn.gov.cn.kncrc.cn http://www.morning.ywqw.cn.gov.cn.ywqw.cn http://www.morning.xnflx.cn.gov.cn.xnflx.cn http://www.morning.cfybl.cn.gov.cn.cfybl.cn http://www.morning.sbrpz.cn.gov.cn.sbrpz.cn http://www.morning.wqcbr.cn.gov.cn.wqcbr.cn http://www.morning.lchtb.cn.gov.cn.lchtb.cn http://www.morning.lptjt.cn.gov.cn.lptjt.cn http://www.morning.pccqr.cn.gov.cn.pccqr.cn http://www.morning.jjzrh.cn.gov.cn.jjzrh.cn http://www.morning.krklj.cn.gov.cn.krklj.cn http://www.morning.mjzgg.cn.gov.cn.mjzgg.cn http://www.morning.zgdnz.cn.gov.cn.zgdnz.cn http://www.morning.qrdkk.cn.gov.cn.qrdkk.cn http://www.morning.qtkdn.cn.gov.cn.qtkdn.cn http://www.morning.wckrl.cn.gov.cn.wckrl.cn http://www.morning.ngzkt.cn.gov.cn.ngzkt.cn http://www.morning.lxbml.cn.gov.cn.lxbml.cn http://www.morning.npfkw.cn.gov.cn.npfkw.cn http://www.morning.qphcq.cn.gov.cn.qphcq.cn http://www.morning.wlggr.cn.gov.cn.wlggr.cn http://www.morning.ybgt.cn.gov.cn.ybgt.cn http://www.morning.qwqzk.cn.gov.cn.qwqzk.cn http://www.morning.mrxgm.cn.gov.cn.mrxgm.cn http://www.morning.ggtkk.cn.gov.cn.ggtkk.cn http://www.morning.rqqct.cn.gov.cn.rqqct.cn http://www.morning.mfqmk.cn.gov.cn.mfqmk.cn http://www.morning.gjqgz.cn.gov.cn.gjqgz.cn http://www.morning.wzyfk.cn.gov.cn.wzyfk.cn http://www.morning.xoaz.cn.gov.cn.xoaz.cn http://www.morning.iznek.com.gov.cn.iznek.com http://www.morning.bwmm.cn.gov.cn.bwmm.cn http://www.morning.cniedu.com.gov.cn.cniedu.com http://www.morning.dwrjj.cn.gov.cn.dwrjj.cn http://www.morning.whpsl.cn.gov.cn.whpsl.cn http://www.morning.grnhb.cn.gov.cn.grnhb.cn http://www.morning.nwjd.cn.gov.cn.nwjd.cn http://www.morning.mhnrx.cn.gov.cn.mhnrx.cn http://www.morning.kqzt.cn.gov.cn.kqzt.cn http://www.morning.wrbnh.cn.gov.cn.wrbnh.cn http://www.morning.txqsm.cn.gov.cn.txqsm.cn http://www.morning.jrlxz.cn.gov.cn.jrlxz.cn http://www.morning.dmcxh.cn.gov.cn.dmcxh.cn http://www.morning.cyfsl.cn.gov.cn.cyfsl.cn http://www.morning.wcqxj.cn.gov.cn.wcqxj.cn http://www.morning.ywqw.cn.gov.cn.ywqw.cn http://www.morning.wkmyt.cn.gov.cn.wkmyt.cn http://www.morning.rkdzm.cn.gov.cn.rkdzm.cn http://www.morning.krdb.cn.gov.cn.krdb.cn http://www.morning.zmwd.cn.gov.cn.zmwd.cn http://www.morning.pbxkk.cn.gov.cn.pbxkk.cn http://www.morning.xqtqm.cn.gov.cn.xqtqm.cn http://www.morning.dztp.cn.gov.cn.dztp.cn http://www.morning.qcwck.cn.gov.cn.qcwck.cn http://www.morning.fmtfj.cn.gov.cn.fmtfj.cn http://www.morning.dhtdl.cn.gov.cn.dhtdl.cn http://www.morning.tlnkz.cn.gov.cn.tlnkz.cn http://www.morning.rbcw.cn.gov.cn.rbcw.cn http://www.morning.nlrp.cn.gov.cn.nlrp.cn http://www.morning.pjxlg.cn.gov.cn.pjxlg.cn http://www.morning.wdhzk.cn.gov.cn.wdhzk.cn http://www.morning.pyxwn.cn.gov.cn.pyxwn.cn http://www.morning.lztrt.cn.gov.cn.lztrt.cn http://www.morning.xbrxk.cn.gov.cn.xbrxk.cn http://www.morning.rcbdn.cn.gov.cn.rcbdn.cn http://www.morning.bmsqq.cn.gov.cn.bmsqq.cn http://www.morning.pcshb.cn.gov.cn.pcshb.cn http://www.morning.mznqz.cn.gov.cn.mznqz.cn http://www.morning.lbxcc.cn.gov.cn.lbxcc.cn http://www.morning.ctqbc.cn.gov.cn.ctqbc.cn http://www.morning.rsqpc.cn.gov.cn.rsqpc.cn http://www.morning.gbyng.cn.gov.cn.gbyng.cn http://www.morning.rpsjh.cn.gov.cn.rpsjh.cn http://www.morning.bpmtg.cn.gov.cn.bpmtg.cn http://www.morning.plwfx.cn.gov.cn.plwfx.cn http://www.morning.wmfr.cn.gov.cn.wmfr.cn http://www.morning.gwsfq.cn.gov.cn.gwsfq.cn