uniApp开发小程序项目实战中遇到的技术问题汇总

1,592 阅读6分钟

uniApp开发小程序项目实战中遇到的技术问题汇总

项目中的问题:

  • 怎么获取API?
  • 怎么实现列表分页?怎么进行搜索查询?
  • 返回上一页,并且执行上一页的方法?向上一页传参数
  • 表单提交?
  • 图片上传,发送请求
  • 图片上传--预览区域
  • 区域-点位下拉选择联动实现--【相应不及时出来$nextTick】
  • 微信分享的实现
  • 是否订阅发送消息,即:微信通知
  • 将当前日期转换为 YYYY-MM-DD,时间为null判断为空
  • Vue里把数组arr1中,join_uniquecode,service_time提取出来组成arr2中格式的新数组?
  • 时间兼容 ios
  • uniapp中判断为空isEmpty
  • 页面跳转,向跳转的页面传递参数,并如何获取?
  • 获取到后端的列表需要在数组里新增字段?
  • 验证手机号码和固话、验证正整数、验证姓名身份证
  • canvas绘制证书图片并且保存到本地
  • canvas绘制图片,手机端二次进入img.onload会不执行?
  • 跳转地址判断,是否是外部链接?
  • 跳转“腾讯公益”小程序
  • 跳转其他小程序
  • 图片、背景图片根据域名实现动态加载
  • uni中Swiper跳转到指定item的实现
  • 上一页下一页3个箭头动画引导效果css+image实现||底部下滑引导箭头(旋转即可)
  • 从微信上粘贴过来的图片在h5上打开会出现“此图片来自微信公众平台未经允许不可引用”
  • 图片上传两种接口传递方式
  • 其他

项目结束总结:

怎么获取API?

get方式获取:

//获取组织列表
getorglist(){
    let _this=this;
    _this.$api.request({
        url:`/client/szzyz/orglist?PageIndex=1&PageSize=100`,
        method:'GET',
    }).then(data=>{
        if(data.data.code==200){
            console.log("getorglist",JSON.stringify(data));
            _this.allOrgList = data.data.data;	
        }
    })
}

// 需要加用户信息
getZyzInfo() {  
    let _this = this;
	//获取志愿者信息
	_this.$api.request({
		header: {
			Authorization: 'Bearer ' + uni.getStorageSync("dt_client_access_token"),
		},
		url: `/client/szzyz/getzyzinfo`,
		method: 'GET',
	}).then(data => {
		_this.userInfo = data.data.data;
        
		console.log(_this.userInfo)  
	})
}

post提交:

joinTeam(){
    let _this=this;
    _this.$api.request({
        url:`/client/szzyz/applyjoinorg`,
        method:'POST',
        data:{
            isfulltime:'否',
            org_uniquecode:this.teamInfo.uniqueCode
        }
    }).then(data=>{
        if(data.data.code==200){	
            uni.showToast({
                icon: "none",
                title: data.data.info,
            });
            let pages = getCurrentPages();
            let prevPage = pages[pages.length - 2]; //上一个页面
            setTimeout(()=>{
                uni.navigateBack({
                    delta: 1
                });
            },1000)
        }
    })
}

怎么实现列表分页? 怎么进行搜索查询?

<view class="activity-all-list" v-if="activityData.length > 0">
    <scroll-view 
    class="list-height" scroll-y="true" show-scrollbar="false" 
    :refresher-triggered="triggered"
    :refresher-threshold="100"
    refresher-enabled="true"
    @scrolltolower="scrolltolower" 
    @refresherrefresh="onRefresh"
    @refresherpulling="onPulling($event)">
                <view class="activity-all-item" :key="item.uniqueCode"  v-for="item in activityData" @tap="navigateDetailTo(item.uniqueCode, item.act_status)">
                    <view class="activity-imgbox"> 
                        <image :src="$util.img(item.act_img)" class="activity-img" mode="widthFix"></image>
                    </view> 
                </view>
    </scroll-view>
</view>
<view class="noData" v-else>
    暂无数据....
</view>
<loading-cover ref="loadingCover"></loading-cover>

data() {
    return {
        activityData: [], 
        pageSize: 10,
        pageIndex: 1, 
        verifyList: {
            page: 1,
            totalPage: 10,
            isLoading: false
        }
    },
    methods: {
        onPulling(e) {
			 	if (e.detail.deltaY < 0) return // 防止上滑页面也触发下拉
			 	this.triggered = true; 
			 },
			 onRefresh() {
			 	this.pageIndex = 1;
			 	this.activityData = [];
			 	this.initData();
			 },
			 scrolltolower() {
			 	this.pageIndex += 1; 
			 	this.initData();
			 },
              async initData() {
				 // 获取数据
			 	let _this = this; 
			 	if (_this.verifyList.isLoading || 
				    (_this.pageIndex != 1 && _this.pageIndex > _this.verifyList.totalPage)) {
                        // 总页数到达最后一页的时候
			 		return;
			 	} 
				_this.verifyList.isLoading = true;
				_this.verifyList.loadingType = 'loading' 
				let url = `/client/szzyz/actlist?PageIndex=${_this.pageIndex}&PageSize=${_this.pageSize}`
				// 搜索关键拼接URL
				if(!_this.$util.isEmpty(_this.lastday)){
					url+=`&lastday=${_this.lastday}`
				} // 搜索日期
				if(!_this.$util.isEmpty(_this.regioncodeD)){
					url+=`&regioncode=${_this.regioncodeD}`
				} // 搜索区域
				if(!_this.$util.isEmpty(_this.acttype_id)){
					url+=`&acttype_id=${_this.acttype_id}`
				} // 搜索类型
				
				let resData = await _this.$api.request({
					url: url,
					method: "GET",
				}).catch((err) => {
					_this.verifyList.isLoading = false;
					_this.verifyList.loadingType = "nomore";
					if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
					if (_this.triggered) _this.triggered = false; 
				}) 
				
			    if(resData) {	
					_this.verifyList.isLoading = false;
					if (_this.triggered) _this.triggered = false;
					if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
					
					if(resData.data.code == 200) {	
						let pageInfo = JSON.parse(resData.header["x-pagination"]); 
						_this.verifyList.totalPage = pageInfo.totalPages;  
						_this.verifyList.loadingType = _this.pageIndex == this.verifyList.totalPage ? 'nomore' : 'more';
						if(!_this.$util.isEmpty(resData.data.data)){
							_this.activityData = _this.activityData.concat(resData.data.data);  
						} 
					}	
				  }  
			 }
    }

返回上一页,并且执行上一页的方法?向上一页传参数

    // 返回上一页面
    let pages = getCurrentPages();
    let prevPage = pages[pages.length - 2]; //上一个页面
    prevPage.$vm.getActlistself(true);//调用上一页的查询列表的方法,向上一页传参数
    setTimeout(()=>{
        uni.navigateBack({
            delta: 1
        }); 
    },1000)

表单提交?图片上传?

<uni-forms :modelValue="formData" :rules="rules" ref="infoForm">
    <uni-forms-item name="orgname">
        <view class="font">团队名称</view>
        <uni-easyinput type="text" v-model="formData.orgname" placeholder="请输入您的团队名称,只支持数字、中文、字母" />
    </uni-forms-item>
    <uni-forms-item class="item-row" name="record">
        <view class="item-clearfix">
            <view class="font label-left">登记备案情况</view>
            <uni-data-checkbox v-model="formData.record" :localdata="records" />
        </view>
    </uni-forms-item>
    <uni-forms-item class="item-row" name="linkphone">
        <view class="item-clearfix">
            <view class="font label-left">负责人电话</view>
            <uni-data-checkbox v-model="formData.showlinkphone" :localdata="phoneOpen" />
        </view>
        <uni-easyinput type="text" v-model="formData.linkphone" placeholder="请输入您的团队负责人电话号码" />
    </uni-forms-item>
    <uni-forms-item name="descs">
        <view class="font">团队介绍</view>
        <uni-easyinput type="textarea" maxlength="200" autoHeight v-model="formData.descs"
            placeholder="请输入您的团队介绍"></uni-easyinput>
    </uni-forms-item>
    <uni-forms-item name="main_img">
        <view class="font">团队LOGO <text class="reason-txt">上传团队Logo,有助于你的团队被识别</text></view>
        <view class="" style="text-align: right;">
            <image v-if="!$util.isEmpty(formData.main_img)" :src="$util.img(formData.main_img)" class="img"
                @tap="reSigin"></image>
            <image v-else src="../static/image/addimg.png" class="img" @tap="reSigin"></image>
        </view>
    </uni-forms-item>
    <uni-forms-item v-if="formData.record=='1'">
        <view class="font">备案材料复印件</view>
        <view class="" style="text-align: right;">
            <image v-if="!$util.isEmpty(formData.recordcopy)" :src="$util.img(formData.recordcopy)"
                class="img" @tap="reSiginFile"></image>
            <image v-else src="../static/image/addimg.png" class="img" @tap="reSiginFile"></image>
        </view>
    </uni-forms-item>
    <uni-forms-item name="regioncode">
        <view class="font">服务区域</view>
        <uni-data-picker placeholder="请选择服务区域" :map="{text:'regionName',value:'regionCode'}"
            popup-title="请选择所属区域" ellipsis :localdata="areaList" v-model="formData.regioncode">
        </uni-data-picker>
    </uni-forms-item>
    <uni-forms-item name="dpid">
        <view class="font">登记、备案主管部门</view>
        <uni-data-picker placeholder="请选择主管部门" popup-title="请选择主管部门" ellipsis :localdata="fundeptList"
            v-model="formData.dpid">
        </uni-data-picker> 
    </uni-forms-item>
</uni-forms> 
    <view class="reg-bot">
        <button class="register-btn" type="warn" size="lg" @tap="submit">提交注册</button>
    </view>

    <label class="teamradio" @tap="teamchecked = !teamchecked">
        <radio class="radio" :checked="teamchecked"
            style="transform:scale(0.7)" color="#2979ff" />
        我已阅读
        <view class="navigator-hover" @tap.stop="isShowDialog = true"> 
        <!-- 阻止冒泡 -->
            《团队注册须知》
        </view>
    </label>
import http from '@/common/js/config.js'
const imgBaseUrl = http.config.imgDomain + '/upload/imgs' // 'http://192.168.1.3:8080'
export default {
		data() {
			return {
				    formData:{
				       name: "",//名称
				       main_img: "",//主图
				       servicetype: "",//服务类型
				       regioncode: "",
				       address: "",
				       descs: "",
				       startDate: "",
				       endDate: "",
					   startTime: "",
					   endTime: "",
				       linkName: "",
				       phone: "",
				       sponsor: "",
				       txmaplan: "",
				       txmaplat: "",
				       recruit_count: null,
				       min_age: 0,
				       servicefield: "",
				       acttype_id: null,
					   servicetime:""//服务时长
				    },
					startDateU: new Date().toISOString().slice(0, 10),
					areaList:[],
					servicelyTypeList:[],
					activityTypeList:[],
					rules:{
						name:{
							rules: [{
									required: true,
									errorMessage: '请输入活动名称',
								}
							]
						},
						startDate:{
							rules: [{
									required: true,
									errorMessage: '请选择活动时间',
								}
							]
						},
						startTime:{
							rules: [{
									required: true,
									errorMessage: '请选择招募开始时间',
								}
							]
						},
						endTime:{
							rules: [{
									required: true,
									errorMessage: '请选择招募结束时间',
								}
							]
						},
						servicetime:{
							rules: [{
									required: true,
									errorMessage: '请输入服务时长',
								}
							]
						},
						regioncode:{
							rules: [{
									required: true,
									errorMessage: '请选择活动区域',
								}
							]
						},
						address:{
							rules: [{
									required: true,
									errorMessage: '请输入活动地点',
								}
							]
						},
						descs: {
							rules: [{
									required: true,
									errorMessage: '请输入活动介绍',
								}
							]
						},
						phone: {
							rules: [{
									required: true,
									errorMessage: '请输入联系人电话',
								},{
								validateFunction: function(rule, value, data, callback) {
									let iphoneReg = /^(13[0-9]|14[1579]|15[0-3,5-9]|16[6]|17[0123456789]|18[0-9]|19[89])\d{8}$/;//手机号码
									let iphoneReg2 = /^(0[0-9]{2,3}\-)([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$/; //固话
									if (!(iphoneReg.test(value)||iphoneReg2.test(value))) {
										callback('联系人电话格式不正确,请重新填写')
									}
								}
							}
							]
						},
						recruit_count: {
							rules: [{
									required: true,
									errorMessage: '请输入招募人数',
								},{
								validateFunction: function(rule, value, data, callback) {
									let numReg = /^[0-9]*$/;//正整数
									if (!numReg.test(value)) {
										callback('只能输入正整数,请重新填写')
									}
								}
							}
							]
						},
						acttype_id: {
							rules: [{
									required: true,
									errorMessage: '请选择类型',
								}
							]
						},
						servicetype: {
							rules: [{
									required: true,
									errorMessage: '请选择服务领域',
								}
							]
						},
						linkName: {
							rules: [{
									required: true,
									errorMessage: '请输入联系人',
								}
							]
						},
						sponsor: {
							rules: [{
									required: true,
									errorMessage: '请输入主办方',
								}
							]
						}
					},
					submitting: false
			};
		},
		methods: {
            //上传
			reSigin() {
				let _this = this;
				uni.chooseImage({
					count: 1,
					success: res => {
						uni.showLoading()
						uni.uploadFile({
							url: http.config.baseUrl + '/client/AddressPunch/UploadAddressPunchImage',
							filePath: res.tempFilePaths[0],
							name: 'files',
							header: {
								"Content-Type": "multipart/form-data",
								Authorization: 'Bearer ' + uni.getStorageSync(
									"dt_client_access_token"),
							},
							formData: {
								user_id: this.userId
							},
							complete: () => {
								uni.hideLoading()
							},
							success: res => {
								const d = res.data ? JSON.parse(res.data) : {};
								_this.formData.main_img = d.data[0].file_path;
							}
						})
					}
				})
			},
			reSiginFile() {
				let _this = this;
				uni.chooseImage({
					count: 1,
					success: res => {
						uni.showLoading()
						uni.uploadFile({
							url: http.config.baseUrl + '/client/AddressPunch/UploadAddressPunchImage',
							filePath: res.tempFilePaths[0],
							name: 'files',
							header: {
								"Content-Type": "multipart/form-data",
								Authorization: 'Bearer ' + uni.getStorageSync(
									"dt_client_access_token"),
							},
							formData: {
								user_id: this.userId
							},
							complete: () => {
								uni.hideLoading()
							},
							success: res => {
								const d = res.data ? JSON.parse(res.data) : {};
								_this.formData.recordcopy = d.data[0].file_path;
								console.log("recordcopy:", _this.formData.recordcopy);
							}
						})
					}
				})
			}, 
            submit() {
				let _this = this;
				// debugger;
				if (!_this.teamchecked) {
					uni.showToast({
						icon: "none",
						title: `请勾选《团队注册须知》 `,
					});
					return;
				}
				_this.$refs.infoForm.validate().then(res => {
					_this.$api.request({
						url: `/client/szzyz/applyorg`,
						method: "POST",
						data: _this.formData
					}).then(res => { 
						uni.showToast({
							icon: "none",
							title: res.data.info,
						});
						if (res.data.code == "200") {
							let pages = getCurrentPages();
							let prevPage = pages[pages.length - 3]; //上一个页面 
							prevPage.$vm.getData();
							setTimeout(() => {
								uni.navigateBack({
									delta: 2
								});
							}, 1000)
						}
					});
				}).catch(err => {
					uni.showToast({
						icon: "none",
						title: "请输入必填项",
					});
				})
			}
        }

图片上传--预览区域(苏青惠打卡)

<view class="clock-in-frame" :style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/clock-in-frame.png)'}]">
    <!-- 图片预览区域 -->
	<image class="upload-img-preview" width="240" v-if='!$util.isEmpty(uploadImgUrl)' :src="uploadImgUrl" ></image>
	<view class="upload-img" 
	:style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/upload-img-bg.png)'}]"
	@tap="uploadImg()">
		<image src="../static/image/clock-in/add-img-icon.png" class="upload-icon"></image>
		<view class="desc">添加图片</view>
		<view class="tips">上传一张点位打卡的照片</view>
	</view>
	<view class="btn">
		<image @tap="uploadImg()" src="../static/image/clock-in/re-select-btn.png" class="img"></image>
		<image @tap="submit()" src="../static/image/clock-in/confirm-btn.png" class="img"></image>
	</view> 
</view>
data() {
	return{
		uploadImgUrl: '',
	}
},
methods:{
	//打卡
	uploadImg(){ 
		let _this = this;
		//判断是否已完善信息
		if(this.$util.isEmpty(_this.personInfo.idcard)){
			uni.showModal({
				title: "提示",
				content: '请先完善信息',
				showCancel: false,
				success: function (e) {
					uni.navigateTo({
						url: '../../../pages/index/personInfo',
					});
				}
			});
		}else{
			//弹框,选取区域和地址
			// 上传图片至预览区
			uni.chooseImage({
				count: 1, //默认9
				// sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
				// sourceType: ['album'], //从相册选择
				success: function (res) {
					_this.uploadImgUrl = res.tempFilePaths[0]
					// console.log('@@@', _this.uploadImgUrl);
					//uni.showLoading();
				}
			});
		}
	},
}

区域-点位下拉选择联动实现--【相应不及时出来$nextTick】(苏青惠打卡)uni-data-select

弹框后出现的表单有验证设置验证规则的时候要加$nextTick
<uni-forms :modelValue="clockFormData" ref="clockForm" label-width="94rpx" >
	<uni-forms-item  name="areaId">
		<image class="label-text" src="../../qingyouwei/static/image/clock-in/area-txt-icon.png"></image>
		<uni-data-select v-model="clockFormData.areaId" :border="false"
		:localdata="areaList" placeholder="请选择打卡区域" @change="areaChange()"></uni-data-select>
	</uni-forms-item>
	<uni-forms-item name="pointId">
		<image class="label-text" src="../../qingyouwei/static/image/clock-in/point-txt-icon.png"></image>
		<uni-data-select ref="pointList" v-model="clockFormData.pointId"
		:border="false" :localdata="pointList" placeholder="请选择打卡点位" @change="pointChange()">></uni-data-select>
	</uni-forms-item>
</uni-forms> 
<view class="area-bottom">
	<image @tap="cancel()" src="../static/image/clock-in/cancel-icon.png" class="img"></image>
	<image @tap="confirm()" src="../static/image/clock-in/confirm-btn.png" class="img"></image> 
</view>
data() {
	return{
		areaList:[],
		pointList:[],
		clockFormData:{
			areaId:'',
			pointId:''
		},
	}
},
onReady() {
	// 需要在onReady中设置规则 
	this.$nextTick(()=>{
		this.$refs.clockForm.setRules(this.rules)
	})
},
methods:{
	areaChange(areaId){
		// 点击区域下拉
		this.$nextTick(()=>{
			this.getPointList(areaId)
		})
	},
	pointChange(pointId){
		// 点击点位下拉
		this.$nextTick(()=>{
			console.log("pointId",pointId)
			this.clockFormData.pointId=pointId;
		})
	},
	//获取区域
	getAreaList(){
		let _this = this;
		_this.$api.request({
			url: `/client/AddressPunch/getarealist`,
			method: "GET"
		}).then(res => {
			// console.log('res@',res.data.data);
			let rang = _this.$util.isEmpty(res.data.data) ? [] : res.data.data;
			rang.forEach((val, index) => {
				_this.areaList.push({
					value: val.id,   // 选项id
					text: val.area_name   // 选项名称
				})
			})
		})
	},
	//获取点位列表
	getPointList(areaId){
		console.log('areaId@', areaId);
		let _this = this;
		_this.pointList = [];
		if(_this.$util.isEmpty(areaId)){
			return;
		}
		_this.$api.request({
			url: `/client/AddressPunch/GetAreaPoints/${areaId}`,
			method: "GET"
		}).then(res => { 
			let rang = _this.$util.isEmpty(res.data) ? [] : res.data;
			rang.forEach((val, index) => {
				_this.pointList.push({
					//value: val.area_id,   // 选项id
					value: index+1,
					text: val.point_name   // 选项名称
				})
			})
		})
	},
	//选择区域提交
	confirm(){
		let _this = this; 
		_this.$refs.clockForm.validate().then(res => { 
			let areaName = _this.areaList.filter(item => {
				return item.value == _this.clockFormData.areaId
			})[0].text;
			let pointName = _this.pointList.filter(item => {
				return item.value == _this.clockFormData.pointId
			})[0].text; 
			uni.showModal({
				title: "提示",
				content: '是否确认提交?',
				showCancel: false,
				success: function (e) { 
					uni.uploadFile({
						url: http.config.baseUrl + '/client/AddressPunch/UploadImage',
						filePath: _this.uploadImgUrl,
						name: 'files',
						header: {
							"Content-Type": "multipart/form-data",
							Authorization: 'Bearer ' + uni.getStorageSync("dt_client_access_token"),
						},
						formData: {
							user_id: _this.userId
						},
						complete: () => {
							uni.hideLoading()
						},
						success: res => {
							const d = res.data ? JSON.parse(res.data) : {};
							_this.$api.request({
								url: '/client/AddressPunch/SubmitAddressPunch',
								method: "POST",
								data: {
									data: { 
										punch_activity_name: '新版打卡',
										user_id: _this.userId,
										address_route: areaName,//区域名称
										address_route_sort: 1,
										title: pointName,//点位名称
										title_sort: 0,//给默认值
										content: ''
									},
									details: d.data
								}
							}).then(res => { 
								if (res.data.code === 200) {
									uni.showToast({
										icon: "success",
										title: "恭喜,打卡成功!",
									}); 
									_this.cancel();
			
								} else {
									uni.showToast({
										title: res.data.info,
										icon: 'error'
									})
								}
							})
						}
					})
				}
			});
		})
	},
}

微信分享的实现

需要是按钮button, 且要添加属性open-type="share", 注意:如果不需要点击按钮触发分享,使用微信顶部‘...’自带分享,只需要配置onShareAppMessage,onShareTimeline2个方法就行了,即可开启微信分享。

<view class="share-box"> 
    <button class="share-btn" open-type="share"><image src="../static/image/share-red-icon.png" class="share-red-icon"></image>分享</button>
</view>
onShareAppMessage(res) {
    return {
        title:`我正在参加${data.name},邀请你来体验!`,
        path:`/subpages/qingzhiyuan/pages/activityDetail?uniqueCode=${this.uniqueCode}&act_status=${this.act_status}`
    }
},
onShareTimeline(res) {
    return {
        title:`我正在参加${data.name},邀请你来体验!`,
        path:`/subpages/qingzhiyuan/pages/activityDetail?uniqueCode=${this.uniqueCode}&act_status=${this.act_status}`
    }
}

是否订阅发送消息,即:微信通知

uni.requestSubscribeMessage({
    //eJjvfImh-hYg7KHsc0PNAbEiQXZR01ghCFAEPKsodqg   测试环境tmplIds
    //vaFwHo-uOTK1XnEob1bPmGb5jm9N5dQJqd5xxJXTKG8   正式环境tmplIds
    tmplIds: ['eJjvfImh-hYg7KHsc0PNAbEiQXZR01ghCFAEPKsodqg'],
    success (res) { 
        _this.getZyzInfo()
    }
})

将当前日期转换为 YYYY-MM-DD

startDate: new Date().toISOString().slice(0, 10)  // 将当前日期转换为 YYYY-MM-DD 格式

new Date() 格式化为"YYYY年MM月"

const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const formattedDate = year + '年' + month + '月';
uniapp时间格式化:
$moment("2023-03-07 23:59:59").format("YYYY-MM-DD")

时间为null判断为空

data.endTime?$moment(data.endTime).format('YYYY-MM-DD'):''

Vue里把数组arr1中,join_uniquecode,service_time提取出来组成arr2中格式的新数组?

let arr1 = [{
	"confirm_time": null,
	"idcode": "32092119901214056411",
	"join_status": 0,
	"jointime": "2023-02-23 09:25:39",
	"service_time": "15",
	"status": 1,
	"truename": "www",
	"uniquecode": "351205379a9849c893a7c4e7628b5dd011"
},
{
	"confirm_time": null,
	"idcode": "32092119901214056411",
	"join_status": 0,
	"jointime": "2023-02-23 09:25:39",
	"service_time": "13",
	"status": 1,
	"truename": "www",
	"uniquecode": "849c893a7c4e7628b5dd011"
}]

arr2 = [{
   "join_uniquecode":uniquecode,
    "service_time":service_time
}]
解决:
const arr2 = arr1.map(item => {
  return {
    "join_uniquecode": item.uniquecode,
    "service_time": item.service_time
   }
})

时间兼容 ios

  const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
  const start = new Date();
  const endDate = new Date(this.data.endDate + 'T23:59:59');
  const end = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate(), 23, 59, 59);
  const remainingTime = end.getTime() - start.getTime(); // 结束时间和开始时间的毫秒差
  const remainingDays = Math.round(remainingTime / oneDay); // 毫秒差转为天数并四舍五入

uniapp中判断为空isEmpty

if(!this.$util.isEmpty(uni.getStorageSync("infoRes"))){
	this.infoRes = JSON.parse(uni.getStorageSync("infoRes"));
}

页面跳转,向跳转的页面传递参数,并如何获取?

navigateCertificate(){
	uni.navigateTo({
	url: `./volunteerCertificate`
})
},

向跳转的页面传递参数:

 <view @tap="navigateDetailTo(item.uniqueCode, item.act_status)">带参跳转...</view>

 navigateDetailTo(uniqueCode, act_status) {
	let detailUrl = `./activityDetail?uniqueCode=${uniqueCode}&act_status=${act_status}`
	uni.navigateTo({
	url: detailUrl
	});
}

跳转的页面获取参数:

onLoad(e) {
	if(e.uniqueCode){
		this.uniqueCode = e.uniqueCode // this.uniqueCode在data里声明好
	}  
	if (e.act_status) {
		this.act_status = e.act_status 
	}
},

验证手机号码和固话、验证正整数、验证姓名身份证

validateFunction: function(rule, value, data, callback) {
	let iphoneReg = /^(13[0-9]|14[1579]|15[0-3,5-9]|16[6]|17[0123456789]|18[0-9]|19[89])\d{8}$/;//手机号码
	let iphoneReg2 = /^(0[0-9]{2,3}\-)([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$/; //固话
	if (!(iphoneReg.test(value)||iphoneReg2.test(value))) {
		callback('联系人电话格式不正确,请重新填写')
	}
}
/////
validateFunction: function(rule, value, data, callback) {
	let numReg = /^[0-9]*$/;//正整数
	if (!numReg.test(value)) {
		callback('只能输入正整数,请重新填写')
	}
}
//  验证姓名身份证
// 姓名
export const NAME = /^[\u4e00-\u9fa5]+[·•]*[\u4e00-\u9fa5]+$/

// 身份证
/* eslint-disable */
export const IDCARD = /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/

获取到后端的列表需要在数组里新增字段?

let resData = await _this.$api.request({
	url: url,
	method: "GET",
}).catch((err) => {
	_this.verifyList.isLoading = false;
	_this.verifyList.loadingType = "nomore";
	if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
	if (_this.triggered) _this.triggered = false; 
}) 

if(resData) {	
	_this.verifyList.isLoading = false;
	if (_this.triggered) _this.triggered = false;
	if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
	
	if(resData.data.code == 200) {	
		let pageInfo = JSON.parse(resData.header["x-pagination"]); 
		_this.verifyList.totalPage = pageInfo.totalPages;  
		_this.verifyList.loadingType = _this.pageIndex == this.verifyList.totalPage ? 'nomore' : 'more';
		if(!_this.$util.isEmpty(resData.data.data)){
			_this.activityData = _this.activityData.concat(resData.data.data);  
		}
        // 新增字段
		_this.activityData.forEach(item=>{
			if(item.status==0){
				_this.$set(item,"showStatus",0)//审批中
				_this.$set(item,"showStatusName","审批中")//审批中
			}
			if(item.status==2){
				_this.$set(item,"showStatus",2)//审批退回
				_this.$set(item,"showStatusName","审批退回")
			}
			if(item.status==1 && item.act_status==1){
				_this.$set(item,"showStatus",3)//报名中
				_this.$set(item,"showStatusName","报名中")
			}
			if(item.status==1 && item.act_status==2){
				_this.$set(item,"showStatus",4)//报名结束,活动进行中
				_this.$set(item,"showStatusName","进行中")
			}
			if(item.status==1 && item.act_status==3){
				_this.$set(item,"showStatus",5)//活动已结束
				_this.$set(item,"showStatusName","已结束")
			}
		}
		// 类型判断后新增字段
		_this.activityData.forEach(item => {
			// 类型tag样式判断
			switch (item.acttype_name) {
				case "卫生健康":
				case "为老服务":
				case "阳光助残":
				case "应急救援":
				case "关爱少年儿童":
					_this.$set(item,"acttypeTagClass", "tag-red") 
					break;
				case "禁毒教育":
				case "环境保护":
				case "垃圾分类":
					_this.$set(item,"acttypeTagClass", "tag-green")
					break;
				case "法律服务":
				case "其他领域":
				case "邻里守望":
				case "文化传播":
				case "大型赛会服务":
					_this.$set(item,"acttypeTagClass", "tag-yellow")
					break;
				default:
					_this.$set(item,"acttypeTagClass", "tag-blue")
			} 
		})
	}	
	} 

uniapp如何配置单页背景色

在项目根目录文件pages.json下配置

{
	"path": "pages/signActivitySuccess", // 活动报名成功
	"style": {
		"navigationBarTitleText": "",
		"enablePullDownRefresh": false,
		"navigationBarBackgroundColor": "#B83328",
		"navigationBarTextStyle": "white"
	}
}

uniapp如何配置单页顶部个性化

{
	"path": "pages/voluntaryService",
	"style": {
		"navigationStyle": "custom" // 设置为custom,就不继承通用顶部,可以自定义
	}
}

个性化通用底部

<view class="head"> 
	<image src="../static/image/szzyz_bg.png" style="width: 750rpx; height: 510rpx; position: absolute; left: 0; top: 0;"></image>
	<view class="back" @tap="goBack">
		<uni-icons type="back" size="23" color="#FFFFFF"></uni-icons>
	</view>
	<image class="qzy-txtimg" :src="$util.img('/upload/zyz/qzy_txt.png')"></image>
</view>
.head {
	width: 750rpx;
	height: 510rpx;
	display: flex;
	flex-direction: column;
	background-color: #D73D3B; 
	.back{
		// position: relative;
		position: fixed;  margin-top: 67rpx; margin-left: 27rpx; 
	}
	.qzy-txtimg {
		position: relative;
		width: 604rpx;
		height: 78rpx;
		margin-left: 70rpx;
		margin-top: 215rpx;
	}
}

canvas绘制证书图片并且保存到本地

<template>
    <view class="volunteer-certificate"> 
		<!-- <image class="img"  :src="$util.img('/upload/zyz/certificate_bg.png')"></image> -->
        <image class="ewm"
         :style="{ width: canvasObj.w + 'rpx', height: canvasObj.h + 'rpx' }"
         :src="downPic" 
         :show-menu-by-longpress="true"></image>
        
         <view class="text-center" v-show="downPic">
             <button type="primary" class="saveImage-btn"  @tap="saveImage">保存图片</button>
         </view>
        <canvas
              type="2d"
              id="canvas"
              class="canvas"
              canvas-id="canvas"
              :style="{ width: canvasObj.w + 'rpx', height: canvasObj.h + 'rpx' }"
         ></canvas>
         
    </view>
</template>
<script>
    export default {
        
        data() {
            return {
				bgImg: '/upload/zyz/certificate_bg.png',
                //bgImg:"https://ticket.meipinyun.com/upload/zyz/certificate_bg.png", 
                // bgImg:'../static/image/certificate_bg.png',
                canvasObj: {
                    w: 722,
                    h: 876,
                },
                ctx: null,
                canvas: null,
                downPic:"", 
				userInfo: {}
            }
        },
        onLoad(){
            this.getZyzInfo()
        },
        computed: {
            formattedDate() {
                const date = new Date();
                const year = date.getFullYear();
                let month = date.getMonth() + 1;
                month = month < 10 ? "0" + month : month
                const formattedDate = year + '年' + month + '月';
                return formattedDate 
            }
        },
        methods: {
            getZyzInfo() {  
                let _this = this;
				//获取志愿者信息
				_this.$api.request({
					header: {
						Authorization: 'Bearer ' + uni.getStorageSync("dt_client_access_token"),
					},
					url: `/client/szzyz/getzyzinfo`,
					method: 'GET',
				}).then(data => {
                    if(data.data.code == 200) {
                        _this.userInfo = data.data.data;
                        _this.darwAwardFn();
                    }
				})
            },
            async darwAwardFn() {
                uni.showLoading({
                    title: '证书生成中...'
                });
                let that=this;
                uni.createSelectorQuery()
                .select('#canvas')
                .fields({ node: true, size: true })
                .exec((res) => {
                   //开始画图
                    console.log('获取到的canvas元素res', res)
                    that.canvas = res[0].node
                    that.canvas.width = that.canvasObj.w
                    that.canvas.height = that.canvasObj.h
                    
                    that.ctx = that.canvas.getContext('2d')
                    that.ctx.clearRect(0, 0, that.canvas.width, that.canvas.height);
					console.log('开始画图');
                    that.canvasDraw().then(res=>{ 
						console.log('渲染文字', res)
                        // 渲染文字
                        that.txt()
                    }).then(()=>{
						console.log('生成图片', res)
                        // canvas生成图片 
                        that.canvasImg();
                    })
                })
            },  
            canvasDraw() {
                // 设置背景图
                let that=this;
                return new Promise(res=>{
					console.log("设置背景图",res); 
                    let img = that.canvas.createImage(); //创建img对象
                    img.src = this.$util.img(that.bgImg) + '?' + new Date().getTime(); 
                    img.onload = () => {
                        console.log("complete",img.complete); //true 
                        that.ctx.drawImage(img, 20, 30, that.canvasObj.w, that.canvasObj.h);
                        setTimeout(() => {
                            res(true)
                        }, 100); 
                    };  
                })
            },    
            txt() {
                // 设置文本字体、大小和样式
                let that=this;    
                const fontSize = 24;
                that.ctx.font = `${fontSize}px sans-serif`;
                that.ctx.textBaseline = 'top';  
                // 获取字符串的宽度和高度
                const x = 100
                const y = 340 // 340
                const textHeight = fontSize * 1.2; // 设置文本的高度为字体大小的 1.2 倍
                that.ctx.fillStyle = 'black';
                
                const prefix = '尊敬的';
                const name = that.userInfo.name; 
                const dearcontent = `${prefix}${name}先生/女士`;
                const prefixWidth = that.ctx.measureText(prefix).width + 4; 
                const nameWidth = that.ctx.measureText(name).width + 8;  
                that.letterspacing(dearcontent,x,  y)
                // 绘制一个红色下划线 
                that.ctx.strokeStyle = '#B83328';
                that.ctx.lineWidth = 2;
                that.ctx.beginPath();
                that.ctx.moveTo(x + prefixWidth, y + textHeight);
                that.ctx.lineTo(x + prefixWidth + nameWidth, y + textHeight);
                that.ctx.stroke();

                const pretext = "截止" // 也可以用作2个字符的宽度
                const year = 2023
                const yeartext = "年"
                const month = 10
                const date = that.formattedDate
                const dateTxt = `${pretext}${date},您参与的志愿服务时长已`
                
                const pretextWidth = that.ctx.measureText(pretext).width + 4
                const yearWidth = that.ctx.measureText(year).width + 2
                const yeartextWidth = that.ctx.measureText(yeartext).width + 8
                const monthWidth = that.ctx.measureText(month).width + 4
                that.letterspacing(dateTxt,x + pretextWidth,  y + textHeight * 2)

                // 画下划线
                that.ctx.beginPath();
                that.ctx.moveTo(x + pretextWidth*2, y + textHeight * 3);
                that.ctx.lineTo(x + pretextWidth*2 + yearWidth, y + textHeight * 3);
                that.ctx.stroke();
                // 画下划线
                that.ctx.beginPath();
                that.ctx.moveTo(x + pretextWidth*2 + yearWidth + yeartextWidth, y + textHeight * 3);
                that.ctx.lineTo(x + pretextWidth*2 + yeartextWidth + yearWidth + monthWidth, y + textHeight * 3);
                that.ctx.stroke();
                
                const servertime = that.userInfo.servertime
                const content1 = `累计达到${servertime}小时。符合苏州市志愿者评定标准。`
                that.letterspacing(content1,x,  y + textHeight * 4)

                const servertimeWidth = that.ctx.measureText(servertime).width + 8
                // 画下划线
                that.ctx.beginPath();
                that.ctx.moveTo(x + pretextWidth*2, y + textHeight * 5);
                that.ctx.lineTo(x + pretextWidth*2 + servertimeWidth, y + textHeight * 5);
                that.ctx.stroke();

                const content2 = "感谢您为苏州志愿者服务事业做出的贡献!"    
                that.letterspacing(content2,x,  y + textHeight * 6)
                
                const content3 = '特发此证。'
                that.letterspacing(content3,x,  y + textHeight * 9)
                const pingtaiTxt = "苏州市志愿者服务平台"
                const endDate = that.formattedDate
                // 计算文本宽度
                const pingtaiTxtWidth = that.ctx.measureText(pingtaiTxt).width;
                const endDateWidth = that.ctx.measureText(endDate).width;
                // 绘制文本
                that.letterspacing(pingtaiTxt,that.canvasObj.w - 42 - pingtaiTxtWidth,  y + textHeight * 13)
                that.letterspacing(endDate,that.canvasObj.w - 80 - endDateWidth,  y + textHeight * 15)
            }, 
            canvasImg() {
                //canvas生成图片  
                let that=this;
                uni.canvasToTempFilePath({
                    canvas:that.canvas,
                    success: function (res) {
                        console.log('生成图片成功:')
                        console.log(res)
                        uni.hideLoading();
                        that.downPic = res.tempFilePath 
                    },
					fail:function(err){
						console.log('生成图片失败:')
						console.log(err)
					}
                })  
            },
            letterspacing(content, x, y) {
                let that = this
                let currentX = x;
                for (let i = 0; i < content.length; i++) {
                    that.ctx.fillText(content[i], currentX, y);
                    currentX += that.ctx.measureText(content[i]).width + 2;
                }
            },
            saveImage() {
                var _this = this;
                uni.saveImageToPhotosAlbum({
                    filePath: _this.downPic,
                    success() {
                      uni.showToast({
                      	title: "图片已保存图片到相册",
                      	icon: 'none',
                      	duration: 2000
                      })
                    },
					fail() {
						uni.hideLoading()
						uni.showModal({
							content: '检测到您没打开获取信息功能权限,是否去设置打开?',
							confirmText: "确认",
							cancelText: '取消',
							success: (res) => {
								if (res.confirm) {
									uni.openSetting({
										success: (res) => {
											console.log(res);
											uni.showToast({
												title: "请重新点击保存图片~",
												icon: "none"
											});
										}
									})
								} else {
									uni.showToast({
										title: "保存失败,请打开权限功能重试",
										icon: "none"
									});
								}
							}
						})
					}
                }) 
            }
             
        }
    }
</script>

<style  lang="scss">
.volunteer-certificate{ 
    .text-center{
        text-align: center;
    }
    .ewm{ 
        display:block; 
    }   
    .canvas{
       //display: none; 会导致ios下无法生成
	   //让画布的位置固定在屏幕之外
	   left:9000px;width:1200px;height:1500px;position:fixed;
    } 
    .saveImage-btn{
        margin-top: 92rpx;
		width: 300rpx;
        height: 54rpx;
        background: #B83328;
        border-radius: 19rpx; 
		 font-size: 30rpx;
		 font-family: SourceHanSansSC;
		 font-weight: 500;
		 color: #FFFFFF;
		 line-height: 54rpx;

    }
    
}

</style> 

canvas绘制图片,手机端二次进入img.onload会不执行?使用了方法二

原因:第一次绘制好的图片有缓存
解决:

  1. 使用以下代码来检查图片是否已经被缓存:测试本项目手机端没有用!!!
if (img.complete && img.naturalWidth !== 0) {
  // 如果图片已经被缓存,则直接标记为已加载完成
  that.isLoaded = true;
  that.ctx.drawImage(img, 20, 30, that.canvasObj.w, that.canvasObj.h);
  res(true);
  return;
}

// 这段代码将检查图片是否已经被缓存,并且使用img.naturalWidth来确保图片已经加载完成。如果图片已经被缓存,它将直接进行绘制并完成Promise

2.强制浏览器不要缓存图片。您可以在图片URL上添加随机参数,图片地址为服务器地址

img.src = that.bgImg + '?' + new Date().getTime(); 

跳转地址判断,是否是外部链接?

navigateTo(id, linkUrl,articleAlbums) {
	let url="";
	if(!this.$util.isEmpty(linkUrl)){
		if(linkUrl.indexOf('http')>-1||linkUrl.indexOf('https')>-1){//判断是否是外部链接
			url=`../../../pages/index/webView?linkUrl=${encodeURIComponent(linkUrl)}`
		}else{
			url=`../../../pages/index/activityNewsDetail?id=${id}`
		}
	}else{
		if(this.$util.isEmpty(articleAlbums)){
			url=`../../../pages/index/detail?id=${id}`
		}else{
			url=`../../../pages/index/pictureDetail?id=${id}`
		}
	}
	// let url=!this.$util.isEmpty(linkUrl) ? `../../../pages/index/webView?linkUrl=${encodeURIComponent(linkUrl)}`:
	// 	(this.$util.isEmpty(articleAlbums)?`../../../pages/index/detail?id=${id}`:`../../../pages/index/pictureDetail?id=${id}`);
	uni.navigateTo({
		url: url
	});
}

//////////////
navigateToFundation() { // https://www.shanyuanfoundation.com/ 
	let linkUrl = 'https://www.shanyuanfoundation.com/'
	let url = `/pages/index/webView?linkUrl=${encodeURIComponent(linkUrl)}` 
	uni.navigateTo({
		url: url
	}); 
},

跳转“腾讯公益”小程序

url:   _this.donateUrl = id === 1 ? "/pages/detail/main?pid=1000037096&gt=sub2xq" : (id === 3 ? "/pages/detail/main?pid=1000037101&gt=sub2xq" : '')
jumpWebView(url){
	uni.navigateToMiniProgram({
		appId: 'wxfdcee92a299bcaf1',
		path: url,
		success(res) {
		// 打开成功
		}
	})
}

跳转其他小程序

	onLoad() {
			//跳转其他外部小程序中转页
			/*
				sit-appid:wxc73621641c1fde5e
				uat-appid:wx278e248d7dbf8f9b
				prd-appid:wx65a1739c4139c76d
				页面链接:/packageVip/pages/equityCollection/index
			*/
			let appid = 'wx278e248d7dbf8f9b'
			let url = '/packageVip/pages/equityCollection/index'
			this.jumpWebView(url, appid);
		},
		methods: {
			jumpWebView(url,appid){  
				//跳转其他外部小程序中转页 
				let _this = this
				uni.navigateToMiniProgram({
					appId: appid,
					path: url,
					envVersion: 'release',
					success(res) {
						// 跳转成功的回调函数
						console.log("跳转成功")
						if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
					},
					fail: function (err) {
						// 跳转失败的回调函数
						console.error("跳转失败",err);
						if (_this.$refs.loadingCover) _this.$refs.loadingCover.hide();
					}
				}) 
			} 
		}

图片、背景图片根据域名实现动态加载

<view class="content" 
	:style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/clock-bg.png)'}]">背景图片动态加载示例
</view>

import http from '@/common/js/config.js'
data(){
	return {
    	imgBaseUrl: http.config.imgDomain + '/upload',
	}
}
IMG图片动态加载示例
	<image :src="$util.img('/upload/AddressPunch/policy-info.png')" class="info"></image>

uni中Swiper跳转到指定item的实现

<swiper indicator-dots="true" :autoplay="false" 
@change="swiperChange"
:current="currentItem"
indicator-color="#f0f8ff" indicator-active-color="#80B1FF" class="body">
	<swiper-item key="1" class="info-1"
		:style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/index-bg.png)'}]"
	> 
		<!-- 箭头 -->
		<view class="rightarrow" @tap="goToItem(1)">
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
		</view>
		<image src="../../qingyouwei/static/image/clock-in/logo-icon.png" class="login-icon"></image>
		<image class="title" :style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/clock-title.png)'}]" lazy-load></image> 
		<!-- <view class="point"></view> -->
		<!--区域-->
		<image v-for="item in pointList1" :key="item.id" :src="$util.img(item.area_img)" :style="item.area_css" @tap="jumpDetail(item.id)" lazy-load></image>
	</swiper-item>
	<swiper-item key="2" class="info-2"
		:style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/index-2-bg.png)'}]"
	> 
		<!-- 箭头 -->
		<view class="leftarrow"  @tap="goToItem(0)">
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
			<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
		</view>
		<image src="../../qingyouwei/static/image/clock-in/logo-icon.png" class="login-icon"></image>
		<image class="title" :style="[{backgroundImage:'url(' + imgBaseUrl + '/AddressPunch/clock-title.png)'}]" lazy-load></image>
		<!--区域-->
		<image v-for="item in pointList2" :key="item.id" :src="$util.img(item.area_img)" :style="item.area_css" @tap="jumpDetail(item.id)" lazy-load></image>
	</swiper-item>
</swiper>
data () {
	return () {
		currentItem: 0
	}
},
methods:{
	swiperChange(e) {
		this.currentItem = e.detail.current 
	},
	goToItem(index) { 			  
		this.currentItem = index 
	}
}

上一页下一页3个箭头动画引导效果css+image实现||底部下滑引导箭头(旋转即可)

其中箭头图片可以用样式实现,也可以
<view class="leftarrow" >
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
</view>
<view class="rightarrow" >
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
	<image src="../../qingyouwei/static/image/clock-in/arrowlr.png"></image>
</view>
// 左右箭头
 .leftarrow, .rightarrow {
    top: 980rpx;
    left: 10rpx;
    width: 90rpx;
    height: 70rpx; 
    cursor: pointer;
    display: flex;
    position: absolute;
    z-index: 2;
	image{
		width: 28rpx; height: 70rpx;
		animation: arrow-animation 2s infinite;
		animation-delay: -0.5s;
		&:first-child{
			left: 25rpx;
			animation-delay: -1s;
		}
		&:last-child{
			left: 50rpx;
			animation-delay: -0s;
		}
	}
  } 
	.leftarrow{ 
		transform: rotate(-180deg);  
	}
   .rightarrow { 
		left: auto;
		right: 10rpx; 
   }
 
  @keyframes arrow-animation {
     0%, 100% {
		 opacity: 0.1;
	 }
	 40% {
		 opacity: 1; /* 逐渐显示箭头 */
	 }
	 80% {
		 opacity: 0; /* 保持箭头可见 */
	 }
  }

从微信上粘贴过来的图片在h5上打开会出现“此图片来自微信公众平台未经允许不可引用”

  • 解决办法1: 在页面组件中动态设置:
    如果静态配置不可行,您也可以考虑在页面的 Vue 组件中动态添加 meta 标签。
    例如,在页面的 onLoad 生命周期钩子或 mounted 钩子中,使用 JavaScript 动态向头部添加 meta。
    这段代码会在页面加载后创建一个新的 <meta name="referrer" content="never"> 标签,并将其添加到 HTML 头部。
	onLoad(e){
		// 头部加 <meta name="referrer" content="never">,浏览器可以访问微信公众号的图片
			let meta = document.createElement('meta');
			meta.name = "referrer";
			meta.content = "never";
			meta.content = "no-referrer";
			document.getElementsByTagName('head')[0].appendChild(meta);
		// 头部加 <meta name="referrer" content="never">,浏览器可以访问微信公众号的图片	--end
	}
  • 解决办法2: 使用自定义的 index.html 模板。 首先,在项目的根目录下创建一个新的 index.html 文件,如果已经存在可以直接修改。 在这个文件中,你可以添加你想要的任何 meta 标签。 然后,在 vue.config.js 文件中指定这个模板:
// vue.config.js
module.exports = {
  chainWebpack: config => {
    config
      .plugin('html')
      .tap(args => {
        args[0].template = '你的自定义模板路径'; // 例如 './public/index.html'
        return args;
      });
  }
};

  • 解决办法3: 找到 index.html 文件:在你的 uni-app 项目中,找到 index.html 文件。这通常在项目的根目录。
    编辑 index.html:用文本编辑器打开 index.html 文件,在 <head> 部分添加你想要的 meta 标签。例如:
<!DOCTYPE html>
<html>
<head>
    ...
    <meta name="referrer" content="never">
    ...
</head>
<body>
    ...
</body>
</html>

注意事项:请注意,由于某些浏览器安全策略和隐私设置,content="never" 可能不会在所有浏览器中生效。相对于此,可能需要使用其他方法来控制 referrer 策略,例如使用更广泛支持的 content="no-referrer"。

图片上传两种接口传递方式

第一种(苏青慧)
<view class="" style="text-align: right;">
	<image v-if="!$util.isEmpty(formData.main_img)" :src="$util.img(formData.main_img)" class="img"
		@tap="reSigin"></image>
	<image v-else src="../static/image/addimg.png" class="img" @tap="reSigin"></image>
</view>
reSigin() {
    let _this = this;
    uni.chooseImage({
     count: 1,
     success: res => {
      uni.showLoading()
      uni.uploadFile({
       url: http.config.baseUrl + '/client/AddressPunch/UploadAddressPunchImage',
       filePath: res.tempFilePaths[0],
       name: 'files',
       header: {
        "Content-Type": "multipart/form-data",
        Authorization: 'Bearer ' + uni.getStorageSync(
         "dt_client_access_token"),
       },
       formData: {
        user_id: this.userId
       },
       complete: () => {
        uni.hideLoading()
       },
       success: res => {
        const d = res.data ? JSON.parse(res.data) : {};
        _this.formData.main_img = d.data[0].file_path;
       }
      })
     }
    })
   },
第二种(矿区)--method: "FILE", FILE要是大写!!!
<image v-if="item.file_path" :src="item.file_path" class="img" @tap="reSigin(index)">
 </image>
// reSigin(index)--多个上传图片区域
reSigin(index) {
		let _this = this;
		uni.chooseImage({
			count: 1, //默认9
			sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
			sourceType: ['album', 'camera'], //从相册选择和拍照
			success: async (e) => {
				var tempFilePaths = e.tempFilePaths;
				_this.$api.request({
					url: `/upload`,
					method: "FILE",
					data:{ filePath:  tempFilePaths[0] },
				}).then(res=>{
					//console.log('成功:'+res.data);
					const imgList = JSON.parse(res.data);
				});
			}
		});
	},
},

其他

  • res.data.code==200 post给后端接口,返回200即是成功

  • 分页 tab切换时候要重新初始化数据、页码

changeTabs(showStatus, status, act_status){
	// 根据二级tab切换,返回对应的状态列表
	this.nextActiveIndex = showStatus
	this.status = status
	this.act_status = act_status
	this.pageSize = 10;
	this.pageIndex = 1;
	this.selfActList = [];
	this.getActlistself() 
}