uniapp vue3图片 视频上传 两种方式

视频图片上传
主页面

<template>
	<!--意见反馈 -->
  <view 
		:style="{'paddingTop': navMenuHeight}" 
		class="feedback">
		<navBar :navParams="navParams"></navBar>
		<view class="problem">
			<view class="blem">
				遇到的问题/建议
			</view>	
			<view class="text">
				*感谢您的宝贵建议*
			</view>	
		</view>
		<view class="Ineam">
			<view class="veTeam">
				<!-- @blur="leaveInput"
				@focus="getHeight" -->
				<textarea
					class="uni-textarea"
					:adjust-position="false" 
					@input="submit"
					v-model="autograph"
					maxlength="500" 
					:customStyle="{lineHeight: '80rpx'}"
					placeholder="建议您尽可能详细的描述问题,便于运营同学帮您解决"/>
				<view class="num"><text class="yuu">{{autolength}}</text>/500</view>
			</view>
		</view>
		<view class="Upload-ew">
			<view class="ew">
				<view class="upheatd">
					上传截图
				</view>
				<view class="upew">
					<!-- <view class="intalve">
						
					</view> -->
					<filePicker
						ref="imgRulesChild"
						:objPicker="objPicker"
						@afterRead="afterRead"
						@deleteRead="deleteRead"></filePicker>
				</view>
			</view>
		</view>
		<view class="Upload-ew">
			<view class="ew">
				<view class="upheatd">
					上传视频
				</view>
				<view class="upew">
					<filevideo
						ref="videoRulesChild"
						:videoList="videoList"
						@afterVideo="afterVideo"
						@deleteVideo="deleteVideo"></filevideo>
				</view>
			</view>
		</view>
		<view class="btn-ew">
			<view 
				@tap="btnSubmit"
				:class="[autograph.length > 0 ? 'brnve': 'brnve brntyr']">
				提交</view>
		</view>
	</view>
</template>

<script setup lang="ts">
import { ref ,reactive ,onMounted} from 'vue'
import navBar from '@/components/navBar/index.vue'
import filePicker from '../components/filePicker.vue'
import filevideo from '../components/video.vue'
import { submitFeedback } from '@/api/personal/index'
import type { NavBarParams } from '@/components/types/navBar';
import { STORAGE_KEYS } from '@/utils/constant'
import phone from '../static/img/phone.png'

const navMenuHeight = ref(uni.getStorageSync(STORAGE_KEYS.NAV_MENU_HEIGHT))
const title = ref('layout')
const autograph = ref('')
const autolength = ref(0)
// 上传图片
let objPicker = reactive({
	text:'父组件值',
	limit:3,//图片上传数量
	imageValue:[]
})

const videoStr = ref('')
const imageStr = ref('')
const imgRulesChild = ref(null)
const videoRulesChild = ref(null)

// 上传视频
const videoList = reactive([])
const imageList = reactive([])
const navParams:NavBarParams = {
  'bg':'#131220',  //背景色
  'color':'#FFFFFF',  //字体颜色
  'isBack':true, //是否显示返回按钮,由于导航栏是共用的,把所有的东西封装好,
	'isFullScreen':true, // 是否全屏显示
	// 然后有些页面不需要的东西通过条件控制进行显示与隐藏
  'navTitle': '意见反馈' ,//导航标题
  'isSearch':false,//是否显示搜索图标
  list:[]
}
// 页面图片
const pageImg = reactive({
	phone: `background: url('${phone}') center center / cover no-repeat;`,
})
// const goRecharge = () => {
//     if(rechargeRulesChild.value) {
//       rechargeRulesChild.value.goPay()
//       isShowPayType.value = false
//     }
    
//   }
// 提交
const btnSubmit = () =>{
	if(objPicker.imageValue.length>=1){
		imgValStr(objPicker.imageValue,'img')
	}
	if(videoList.length>=1){
		imgValStr(objPicker.imageValue,'video')
	}
	
	if(autograph.value.length>0){
		console.log('autograph=======》',autograph)
		submitfee()
	}
}

const submitfee= () => {
	let params = {
		image:imageStr.value,
		video:videoStr.value,
		content:autograph.value
	}
	submitFeedback(params).then(data => {
		let res:any = data
		if(res.errcode == 0) {
			autograph.value = ''
			autolength.value = 0
			if(imgRulesChild.value) {
				imgRulesChild.value.imageChild()
			}
			if(videoRulesChild.value) {
				videoRulesChild.value.videoChild()
			}
			
			
			objPicker.imageValue.length = 0
			videoList.length = 0
			console.log('点击事件=====》2333',res)
			console.log('点击事件=====》imageValue.length',objPicker.imageValue)
			console.log('点击事件=====》2333',videoList)
		}
	})
}

// 上传视频
const afterVideo = (e:any) =>{
	videoList.length = 0
	videoList.push(...e)
	console.log('afterVideo=========> ',videoList)
	
}
const deleteVideo = (e:any) =>{
	videoList.length = 0
	videoList.push(...e)
	console.log('deleteVideo=========>',videoList)
}

const imgValStr = (e:any,val:string) =>{
	let arr = reactive([])
	e.forEach((item,index)=>{
		arr.push(item.url)
	})
	if(val=='img'){
		imageStr.value = arr.join(',')
		console.log('imageStr.value====>',imageStr.value)
	}else if(val=='video'){
		videoStr.value = arr.join(',')
		console.log('videoStr.value====>',videoStr.value)
	}else {
		videoStr.value = arr.join(',')
	}
	
}
// 上传截图
const afterRead = (e:any) =>{
	objPicker.imageValue.length=0
	objPicker.imageValue.push(...e)
	console.log('afterReadobjPicker.imageValue=========>',objPicker.imageValue)
	
}
const deleteRead = (e:any) =>{
	objPicker.imageValue.length=0
	objPicker.imageValue.push(...e)
	console.log('deleteRead=========>',objPicker.imageValue)
}
// 多行文本框 
const submit = (e:any) => {
	autolength.value = e.detail.value.length
}

// const leaveInput = (event:any) =>{ //输入框失去焦点时触发,event.detail = {value: value}
// 	console.log('e=========>',event)
// 	// Height.value = 20;
// }
// const getHeight = (event:any) =>{ //输入框聚焦时触发,event.detail = { value, height },height 为键盘高度
// 	console.log('获取输入法高度=========>',event)
// 	// Height.value = event.target.height+20;
// }
onMounted(() => {
	
})
</script>

<style lang="scss">
.feedback{
	width: 750rpx;
	min-height: 100vh;
	background-color: #131220;
	// display: flex;
	// overflow:hidden;
	// // flex-direction: column;
	// // align-items: center;
	// justify-content: center;
	overflow: auto; 
	-webkit-overflow-scrolling: touch; 
	overflow-y:unset;
	// 遇到问题
	.problem{
		margin-left: 60rpx;
		margin-top: 80rpx;
		width: 690rpx;
		.blem{
			height: 44rpx;
			line-height: 44rpx;
			font-size: 40rpx;
			font-family: Source Han Sans CN, Source Han Sans CN-Medium;
			font-weight: 500;
			text-align: left;
			color: #ffffff;
		}
		.text{
			margin-top: 24rpx;
			height: 26rpx;
			line-height: 26rpx;
			font-size: 26rpx;
			font-family: Source Han Sans CN, Source Han Sans CN-Regular;
			font-weight: 400;
			text-align: left;
			color: #898990;
		}
	}
	.Ineam{
		width: 750rpx;
		padding-bottom: 40rpx;
		border-bottom: 10rpx solid #1a1b2b;
		margin-top: 80rpx;
		.veTeam{
			width: 710rpx;
			height: auto;
			border-radius: 16rpx;
			background-color: #1f1e2b;
			margin: 0 auto;
			position: relative;
			.uni-textarea{
				width: 670rpx;
				padding: 20rpx 20rpx;
				height: 240rpx;
				background: #1f1e2b;
				border-radius: 16rpx;
				font-size: 30rpx;
				font-family: Source Han Sans CN, Source Han Sans CN-Medium;
				font-weight: 500;
				text-align: left;
				color: #8f8f95;
				line-height: 70rpx;
				line-height:normal;
			}
			.num{
				position: absolute;
				right: 0rpx;
				bottom:20rpx;
				width: 120rpx;
				height: 30rpx;
				line-height: 30rpx;
				font-size: 30rpx;
				color: #8f8f95;
				// display: flex;
				// justify-content: flex-end;
				.yuu{
					color: #8f8f95;
				}
			}
		}
	}
	.Upload-ew{
		width: 750rpx;
		margin-top: 50rpx;
		.ew{
			margin: 0 auto;
			width: 710rpx;
			.upheatd{
				width: 710rpx;
				height: 32rpx;
				font-size: 30rpx;
				font-family: Source Han Sans CN, Source Han Sans CN-Medium;
				font-weight: 500;
				text-align: left;
				color: #ffffff;
			}
			.upew{
				width: 710rpx;
				height: auto;
				display: flex;
				flex-direction: row;
				.intalve{
					width: 160rpx;
					height: 160rpx;
					background-color: #f4f5f7;
					border-radius: 4rpx;
					margin: 0 16rpx 16rpx 0;
					box-sizing: border-box;
				}
			}
		}
	}
	.btn-ew{
		width: 750rpx;
		margin-top: 150rpx;
		margin-bottom: 100rpx;
		.brnve{
			width: 348rpx;
			height: 84rpx;
			line-height:84rpx;
			background: #ea4459;
			font-size: 30rpx;
			font-family: Source Han Sans CN, Source Han Sans CN-Medium;
			font-weight: 500;
			text-align: center;
			color: #ffffff;
			border-radius: 40rpx;
			margin: 0 auto;
		}
		.brntyr{
			opacity: 0.3;
			background: #ea4459;
		}
	}
}
</style>

图片组件

<template>
	<!-- 上传图片组件 -->
	<!-- v-model="objPicker" -->
  <view  class="title">
		<!-- {{title}} 组件 {{objPicker}} -->
		<view class="ew">
			<u-upload
				:fileList="imageValue"
				@afterRead="afterRead"
				@delete="deletePic"
				name="1"
				multiple
				:maxCount="3"
				:previewFullImage="true"
			></u-upload>
		</view>
	</view>
	
</template>

<script setup lang="ts">
import { ref , reactive ,computed ,onMounted ,getCurrentInstance} from 'vue'
const title = ref('layout')
const imageValue = reactive([]);

const {proxy} = getCurrentInstance()//全局定义的路径

// 父组件传值
const props =defineProps(
  {
    objPicker:{
      type:Object,
      required:true
    }
		// fileList:{
		// 	type:Array,
		// 	required:true
		// }
  }
)
const emits=defineEmits(["afterRead","deleteRead"])
// 图片上传 
const uploadImg = (tempFilePaths:any,) =>{
	console.log('err数据返回====》1111111111111111111')
	return new Promise((resolve, reject) => {
		let a = uni.uploadFile({
			url: proxy.$baseUrl + '/common/uploadFile',
			// header: {
			//   'Authorization': getToken() ? getToken() : '',
			// },
			filePath:tempFilePaths.url,
			name: 'file',
			formData: {
				storeType:6,
				fileName: 'jrjz' + new Date().getTime(),
				fileDir: 'deal',
				fileNameType: 0,
				file: tempFilePaths,
			},
			success: (res) => {
				let succ = JSON.parse(res.data)//数据返回字符串解析
				setTimeout(() => {
					resolve(succ.data.url)
				}, 1000)
				// resolve({
				// 	url: succ.data.url,
				// 	extname: 'png',
				// 	name: succ.data.fileName
				// })
			},
			fail:(err)=>{
				console.log('err数据返回====》',err)
			},
		})
		// const path = tempFilePaths.pop();
		// wx.cropImage({
		// 	src: tempFilePaths.url, // 图片路径
		// 	cropScale: '1:1', // 裁剪比例
		// 	success:(res)=>{
				
		// 	},
		// })
	})
}
// 获取上传状态
const	 afterRead = async(event:any) =>{
	// console.log('获取上传状态',e)
	let fileList = imageValue
	// const res = await uploadImg(e.tempFilePaths,1);
	// emits('loghty', props.objPicker.imageValue)
	let lists = [].concat(event.file);
	  let fileListLen = fileList.length;
	  lists.map((item) => {
	    fileList.push({
	      ...item,
	      status: 'uploading',
	      message: '上传中',
	    });
	  });
		console.log('err数据返回====》22222222222')
	  for (let i = 0; i < lists.length; i++) {
	    const result = await uploadImg(lists[i]);
	    let item = fileList[fileListLen];
	    fileList.splice(fileListLen, 1, {
	      ...item,
	      status: 'success',
	      message: '',
	      url: result,
	    });
			console.log('图片上传fileList====》',fileList)
			emits('afterRead',fileList)
	    fileListLen++;
	  }
	console.log('err数据返回====》1111111111111111111')
}
// 获取上传进度
// const progress = (e:any) =>{
// 	console.log('上传进度:',e)
// }

// 删除
const deletePic = (event:any) =>{
	let fileList = imageValue
	// this.$refs.files.upload()
	fileList.splice(event.index, 1);
	// emits('afterRead',fileList)
	console.log('图片删除fileList====》',fileList)
	emits('deleteRead',fileList)
	// emit('deletePic',this[`fileList${event.name}`])
	console.log('删除',event)
}

const imageChild = () =>{
	imageValue.length = 0
}
// 抛出子组件方法让父组件调用
defineExpose({
	imageChild
})
// 上传失败
// const fail = (e:any) =>{
// 	console.log('上传失败:',e)
// }

// // 删除
// const handleDelete = (e:any) =>{
// 	console.log('删除按钮:',e)
// 	const num = props.objPicker.imageValue.findIndex(v => v.url === e.tempFilePath);
	
// 	props.objPicker.imageValue.splice(num, 1);
// 	console.log('删除按钮:num',num)
// 	emits('inChange', props.objPicker.imageValue)
// }
onMounted(() => {
		// itemH.value = Math.ceil(document.body.clientWidth * (90/375))
		// loading.value = false
	})
</script>

<style lang="scss">
	.title{
		margin-top: 40rpx;
		// width: 375rpx;
		height: auto;
		// .ew{
		// 	border: 1px solid red;
		// }
	}
</style>

视频组件

<template>
  <view class="title">
		 <!-- 视频 -->
		<view class="up-video">
			<!-- <view class="up-label">视频:</view> -->
			<view v-show="videoList.length>0" class="up-video-box">
				<view class="v-box" v-for="(item,index) in videoList" :key="index">
					<!--  -->
					<view  class="v-inner" >
						<video style="width: 172px;height: 72px;" :src="item.url"
							 enable-auto-rotation="true"
							 autoplay='true'
							 muted>
						    </video>
					</view>
					<view class="c-icon">
						<u-icon @click="deleteVideo(index)" name="close" color="#fff" size="8"></u-icon>
					</view>
				</view>
				<view v-if="videoList.length<3" class="box-s" @click="videoRead">
					<u-icon name="camera-fill" color="#d3d4d6" size="26"></u-icon>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup lang="ts">
import { ref , reactive,computed,onMounted} from 'vue'
const {proxy} = getCurrentInstance()
const title = ref('layout')
const videoList = reactive([])

// 父组件传值
const props =defineProps(
  // {
  //   videoList:{
  //     type:Array,
  //     required:true
  //   }
  // }
)
// 子组件给父组件穿值
const emits=defineEmits(["afterVideo","deleteVideo"])

const videoRead = () =>{
	// let that = this;
	let arr =reactive([]);
	let strPath = ref('');
	uni.chooseVideo({
		sourceType: ['camera', 'album'],
		success: function (res) {
			arr = res.tempFilePath.split("/");
			strPath = arr[arr.length - 1];
			if(videoList.length>3)return
			videoList.push({
				url: res.tempFilePath,
				videoName: strPath
			});
			addUpload([{
				url: res.tempFilePath,
				videoName: strPath
			}]);
		}
	});
	
}

const addUpload = (videoArr:any) =>{
	
	// let werArr =reactive([]);
	// werArr.push(...videoArr)
	console.log('videoArr===>',proxy.$baseUrl)
	console.log('videoArr.length===>',videoArr.length)
	videoArr.forEach((item:any) => { //这里之所以循环一个一个上传是因为,我是用于小程序端的,目前uniapp不支持微信小程序以文件列表形式上传,
		
		uni.uploadFile({
			url: proxy.$baseUrl + '/common/uploadFile', //需要传图片的后台接口
			filePath: item.url, // 上传图片 通过uni-app的uni-file-picker组件 函数返回
			name: 'file', //文件名字
			formData: {
				storeType:6,
				fileName: 'jrjz' + new Date().getTime(),
				fileDir: 'deal',
				fileNameType: 0,
				file: item,
			},
			success: res => {
				 console.log('videoList==>11111')
				let result = JSON.parse(res.data);
				console.log('props.videoList',videoList)
				videoList.forEach(v => {
					console.log('videoList==>11111')
					
					// console.log('v===>',v)
				 if(v.videoName === item.videoName) {
					 v.url = result.data.url;
					 console.log('v["url"]===>',v.url,'result.data.url==>',result.data.url)
					 // console.log('videoList==>',videoList.length)
				 }
				});
				emits('afterVideo',videoList)
			},
			fail: e => {
				console.log(e)
			}
		});
	});
}
const deleteVideo = (index:any)=> {
	videoList.splice(index, 1);
	emits('deleteVideo',videoList)
}
const tabActiveBg = computed((item:any) => {
	return `<video autoplay style="width: 172px;height: 72px;" "><source src="${item}" type="video/mp4"></video>`
})

const videoChild = () =>{
	videoList.length = 0
}
defineExpose({
	videoChild
})
onMounted(() => {
		// itemH.value = Math.ceil(document.body.clientWidth * (90/375))
		// loading.value = false
	})
</script>

<style lang="scss">
	.title{
		margin-top: 40rpx;
		.up-video {
			display: flex;
		
			.up-video-box {
				// width: calc(100% - 105px);
				display: flex;
				flex-wrap: wrap;
		
				.v-box {
					width: 160rpx;
					height: 160rpx;
					position: relative;
					overflow: hidden;
					margin: 0 16rpx 16rpx 0;
					// padding: 20rpx 20rpx 0rpx 0rpx;
					box-sizing: border-box;
					background: #010101;
		
					.v-inner {
						width: 160rpx;
						height: 160rpx;
						position: absolute;
						bottom: 0rpx;
						left: 0rpx;
					}
		
					.c-icon {
						position: absolute;
						top: -14rpx;
						right: -14rpx;
						background: #373737;
						border-radius: 50%;
						width: 40rpx;
						height: 40rpx;
						display: flex;
						justify-content: center;
						align-items: center;
						padding: 12rpx 12rpx 0px 0px;
						box-sizing: border-box;
					}
				}
		
				.box-s {
					display: flex;
					align-items: center;
					justify-content: center;
					width: 160rpx;
					height: 160rpx;
					background-color: #f4f5f7;
					border-radius: 4rpx;
					margin: 0 16rpx 16rpx 0;
					box-sizing: border-box;
				}
			}
		
		}
		
	}
</style>
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值