uni-app:实现H5的录音功能,并上传到服务器

uni-app:实现H5的录音功能

在H5中录音有很大的限制,需要在https的域名下或者localhost本地下才可 不然会报错



<view>
			<button @tap="startRecord">开始录音</button>
			<button @tap="endRecord">停止录音</button>
			<button @tap="playVoice">播放录音</button>
		</view>
methods: {
			cardSwiper(e) {
				this.cardCur = e.detail.current
			},
			toplay() {
				this.pplay = !this.pplay
				console.log(this.pplay)
			},
			startRecord() {
				console.log('开始录音');
				recorder.start();
				
			},
			endRecord() {
				console.log('录音结束');
				recorder.stop();
				console.log(recorder.duration);//打印出录音的时长
			},
			playVoice() {
				console.log('播放录音');

				
				 recorder.play()
			}
		}

详情可见 https://ext.dcloud.net.cn/plugin?id=566

<file ref='file'  id='file'></file>
  • 此处file为自己编写的一个组件,详情可见底部代码
  • 现在有一个需求就是将录的音转换成音频的形式,上传给服务器
  • 获取缓存中的音频数据,并转换成音频文件的形式,再上传到服务器
zanshidow() {
				// 获取录音
				let blob= recorder.getPCMBlob();
				console.log(
					recorder.getPCMBlob())

				// blob转换成file对象
				let files = new window.File(
					[blob],
					'ex.mp3', {
						type:  'audio/mpeg'
					}
				);
				 console.log(blob.type)
				this.$refs.file.hRequest({
					url: 'http://120.77.251.202:3000/Listen/listen',
					file:files
				});
				console.log(files)
			}

这样就成功返回了
在这里插入图片描述
file.vue代码

<template>
	<view class="">



		<!-- <view class='t-toptips' :style="{top: top,background: cubgColor}" :class="[show?'t-top-show':'']">
			<view v-if="loading" class="flex flex-sub">
				<view class="cu-progress flex-sub round striped active sm">
					<view :style="{ background: color,width: value + '%'}"></view>
				</view>
				<text class="margin-left">{{value}}%</text>
			</view>
			<block v-else>{{msg}}</block>

		</view> -->
		<view ref="input" class="input">

		</view>


	</view>
</template>

<script>
	export default {
		props: {
			//改成id从父组件传进来
			id:{
				type:String,
				default:'file'
			},
			top: {
				type: String,
				default: 'auto'
			},
			bgColor: {
				type: String,
				default: 'rgba(49, 126, 243, 0.5)',
			},
			color: {
				type: String,
				default: '#e54d42',
			}
		},
		data() {
			return {
				cubgColor: '',
				loading: false,
				value: 5,
				show: false,
				msg: '执行完毕~',
				hParam: {}
			}
		},
		mounted() {
			
			// #ifdef H5
			var input = document.createElement('input')
			input.type = 'file'
			// input.accept =  '.zip'
			input.style.display = 'none'
			//之前input的id是固定为‘file’,所以导致一个页面出现了两个id为file的input标签
			input.id = this.id
			input.multiple = "multiple"
			//所以onchange一直指向第一个id为file的方法
			//我们把动态生成的input的id值改成不一样的就可以了
			input.onchange = (event) => {
				console.log(this.id)
				// 上传附件 获取文件信息
				this.fileinfo = event.target.files[0];
				// console.log(this.fileinfo)
				console.log("文件信息", this.fileinfo);
				// $emit触发父组件的方法
				this.$emit('setFileInfo', this.fileinfo);
				//this.upload();
				// this.hRequest(this.hParam)
			}
			this.$refs.input.$el.appendChild(input);
			// #endif


		},
		methods: {
			toast(title = '', {
				duration = 2000,
				icon = 'none'
			} = {}) {
				uni.showToast({
					title,
					duration,
					icon
				});
			},
			getRequest(url) {
				let theRequest = new Object();
				let index = url.indexOf("?");
				if (index != -1) {
					let str = url.substring(index + 1);
					let strs = str.split("&");
					for (let i = 0; i < strs.length; i++) {
						theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
					}
				}
				return theRequest;
			},

			/*
				上传说明:
				currentWebview: 当前窗口webview对象
				url:上传接口地址
				name:上传文件key值
				header: 上传接口请求头
				...:body内其他参数
			*/
			appChooseFile({
				currentWebview,
				url,
				name = 'file',
				header,
				...formData
			} = {}) {
				// #ifdef APP-PLUS
				let wv = plus.webview.create("", "/hybrid/html/index.html", {
					'uni-app': 'none', //不加载uni-app渲染层框架,避免样式冲突
					top: 0,
					height: '100%',
					background: 'transparent'
				}, {
					url,
					header,
					formData,
					key: name,
				});
				wv.loadURL("/hybrid/html/index.html")
				currentWebview.append(wv);
				wv.overrideUrlLoading({
					mode: 'reject'
				}, (e) => {
					let {
						fileName,
						id
					} = this.getRequest(e.url);
					fileName = unescape(fileName);
					id = unescape(id);
					return this.onCommit(
						this.$emit('up-success', {
							fileName,
							data: {
								id,
								statusCode: 200
							}
						})
					);
				});
				// #endif
			},
			wxChooseFile({
				url,
				name = 'file',
				header,
				...formData
			} = {}) {
				wx.chooseMessageFile({
					count: 2,
					type: 'file',
					success: ({
						tempFiles
					}) => {

						let [{
							path: filePath,
							name: fileName
						}] = tempFiles;
						this.setdefUI();

						return uni.uploadFile({
							url,
							name,
							filePath,
							formData,
							header,
							success: (res) => {
								if (res.statusCode == 200) {

									let data = JSON.parse(res.data);

									//可自行添加后台返回状态验证
									return this.onCommit(this.$emit('up-success', {
										fileName,
										data
									}));
								}
								return this.errorHandler('文件上传失败', this.upErr);
							},
							fail: () => this.errorHandler('文件上传失败', this.upErr)
						});
					},
					fail: () => this.errorHandler('文件选择失败', this.upErr)
				})
			},
			hChooseFile({
				url,
				name = 'file',
				header,
				...formData
			} = {}) {
				// #ifdef H5
				// this.hRequest()
				document.getElementById(this.id).click();
				// #endif
			},

			// h5上传请求
			hRequest({
				url,
				file,
				name = 'file',
				header,
				...formData
			} = {}) {


				// let mask = document.querySelector(".mask");
				// let fileDom = document.querySelector(".file");
				// let tis = document.querySelector(".tis");
				// let progress = document.querySelector(".tis-progress");
				// let cancel = document.querySelector(".cancel-btn");


				file = file?file:document.getElementById(this.id).files[0];
				console.log('向后端发送的内容',file)


				let createUpload = (file, url, key = 'file', header = {}, data = {}) => {
					console.log(`
				上传地址:${url}\n
				请求头:${JSON.stringify(header)}\n
				参数:${JSON.stringify(data)}
				`);
					if (!url) {
						return;
					}
					//tis.style.display = 'flex';

					let formData = new FormData();
					formData.append(key, file);

					for (let keys in data) {
						formData.append(keys, data[keys]);
					}

					let xhr = new XMLHttpRequest();
					xhr.open("POST", url, true);

					for (let keys in header) {
						xhr.setRequestHeader(keys, header[keys]);
					}

					// xhr.upload.addEventListener("progress", function(event) {
					// 	if (event.lengthComputable) {
					// 		let percent = Math.ceil(event.loaded * 100 / event.total) + "%";
					// 		// progress.innerText = `努力上传中..${percent}`;
					// 	}
					// }, false);

					xhr.ontimeout = function() {
						// xhr请求超时事件处理
						// progress.innerText = '请求超时';

					};
					
					//监听返回
					xhr.onreadystatechange = (ev) => {
						
						if (xhr.readyState == 4) {
							console.log('status:' + xhr.status);
							uni.hideLoading();
							if (xhr.status == 200) {
								let fileName = file.name;
								// progress.innerText = '上传成功';
								
								console.log('返回数据:' + xhr.responseText);
								this.$emit('fileOk');
								// this.$msg(xhr.responseText+'文件上传成功')
								//location.href = `callback?fileName=${escape(file.name)}&id=${escape(xhr.responseText)}`;

								// return this.onCommit(
								// 	this.$emit('up-success', {
								// 		fileName,
								// 		data: JSON.parse(xhr.response)
								// 	})
								// );
							} else {
								console.log('上传失败')
								// return this.errorHandler('文件上传失败', this.upErr);
							}



						}
					};
					uni.showLoading({
						title: '文件上传中',
						mask: true
					})
					//发送请求
					xhr.send(formData);


				}

				createUpload(file, url, this.filename, header, {});

			},
			/* 
			上传
			*/
			upload(param = {}) {

				if (!param.url) {
					this.toast('上传地址不正确');
					return;
				}

				if (this.loading) {
					this.toast('还有个文件玩命处理中,请稍候..');
					return;
				}


				// #ifdef APP-PLUS
				return this.appChooseFile(param);

				// #endif

				// #ifdef H5
				this.hParam = param;
				return this.hChooseFile(param);

				// #endif

				// #ifdef MP-WEIXIN
				return this.wxChooseFile(param);
				// #endif
			},
			/* 
			打开文件 
			*/
			open(filePath) {
				let system = uni.getSystemInfoSync().platform;
				if (system == 'ios') {
					filePath = encodeURI(filePath);
				}
				uni.openDocument({
					filePath,
					success: (res) => {
						console.log('打开文档成功');
					}
				});
			},
			/* 
			下载
			 type: temporary=返回临时地址,local=长期保存到本地
			 */
			download(url, type = 'temporary') {
				if (this.loading) {
					this.toast('还有个文件玩命处理中,请稍候..');
					return;
				}
				this.setdefUI();

				return new Promise((resolve, reject) => {
					let downloadTask = uni.downloadFile({
						url,
						success: ({
							statusCode,
							tempFilePath
						}) => {
							if (statusCode === 200) {
								if (type == 'local') {
									uni.saveFile({
										tempFilePath,
										success: ({
											savedFilePath
										}) => this.onCommit(resolve(savedFilePath)),
										fail: () => this.errorHandler('下载失败', reject)
									});
								} else {
									this.onCommit(resolve(tempFilePath))
								}
							}
						},
						fail: () => this.errorHandler('下载失败', reject)
					});

					downloadTask.onProgressUpdate(({
						progress = 0
					}) => {
						if (progress <= 100) {
							this.$nextTick(() => {
								this.value = progress;
							});
						}
					});
				})

			},

			onCommit(resolve) {
				this.msg = '执行完毕~';
				this.loading = false;
				this.cubgColor = 'rgba(57, 181, 74, 0.5)';
				setTimeout(() => {
					this.show = false;
				}, 1500);
				return resolve;
			},

			setdefUI() {
				this.cubgColor = this.bgColor;
				this.value = 0;
				this.loading = true;
				this.show = true;
			},

			upErr(errText) {
				this.$emit('up-error', errText);
			},

			errorHandler(errText, reject) {
				this.msg = errText;
				this.loading = false;
				this.cubgColor = 'rgba(229, 77, 66, 0.5)';
				setTimeout(() => {
					this.show = false;
				}, 1500);
				return reject(errText);
			}


		}
	}
</script>

<style scoped>
	.t-toptips {
		width: 100%;
		padding: 18upx 30upx;
		box-sizing: border-box;
		position: fixed;
		z-index: 90;
		color: #fff;
		font-size: 30upx;
		left: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		word-break: break-all;
		opacity: 0;
		transform: translateZ(0) translateY(-100%);
		transition: all 0.3s ease-in-out;
	}

	.t-top-show {
		transform: translateZ(0) translateY(0);
		opacity: 1;
	}
</style>

在这里插入图片描述


版权声明:本文为qq_44429079原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。