项目场景:

使用input调取手机摄像头,录制视频并上传到客户端


问题描述:

<template>
	<div>
		<button>点击上传</button>
		<input type="file" @change="openCamera($event)" accept="video/*" capture="user" />
		<!-- accept="video/*" :accept 属性只能与 <input type="file"> 配合使用。-->
		<!--	它规定能够通过文件上传进行提交的文件类型。 -->
		<!-- 指定capture属性调用默认相机,摄像,录音功能 -->
	</div>
</template>

在input发生change事件时,在测试的时候发现ios的微信内置浏览器无法触发FileReader 的onload事件,以及URL.createObjectURL()。


解决方案:

方法解读:

FileReader.onload:读取成功完成时触发。也可通过onload属性获得。
FileReader.loadend :读取成功或失败时触发。也可通过onloadend属性获得。
FileReader.result :只读 文件的内容。此属性仅在读取操作完成后才有效,并且数据的格式取决于用于启动读取操作的方法。

URL.createObjectURL和FileReader.readAsDataURL:

URL.createObjectURL:静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。
这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象,直接绑定给src即可。
FileReader.readAsDataURL :方法用于读取指定Blob或的内容File。读取操作完成后,readyState变成DONE,并loadend触发。那时,该result属性包含数据作为数据:URL表示文件数据为base64编码的字符串。

主要区别:
通过FileReader.readAsDataURL(file)可以获取一段data:base64的字符串
通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL

错误代码:
经测试,代码安卓的自带浏览器,安卓的微信,均可上传成功,uc浏览器,ios 的微信内置浏览器无法上传,ios Safari可以成功上传。(测试不全)

methods: {
			// 调用摄像头 上传视频
			openCamera(e) {
				let that = this;
				let duration;
				let selectedFile = e.target.files[0];
				let reader = new FileReader(); //这是核心,读取操作就是由它完成.
				reader.onload = function(e) {
					let strContent = this.result;
					//获取视频或者音频时长
					let fileurl = URL.createObjectURL(selectedFile);
					let audioElement = new Audio(fileurl);
					//经测试,发现audio也可获取视频的时长
					audioElement.addEventListener("loadedmetadata", function(_event) {
						duration = audioElement.duration;
						if (duration > 8) {
							that.$message.error("视频时间过长,请重新录制");
						} else {
							that.base64ToFile(strContent);
						}
					});
				};
				reader.readAsDataURL(selectedFile); //读取文件的内容,也可以读取文件的URL
			},
			// 将bes64转成文件
			base64ToFile(base64Data) {
				// base64转blob
				let arr = base64Data.split(","),
					mime = arr[0].match(/:(.*?);/)[1],
					bstr = atob(arr[1]),
					n = bstr.length,
					u8arr = new Uint8Array(n);
				while (n--) {
					u8arr[n] = bstr.charCodeAt(n);
				}
				let blob = new Blob([u8arr], {
					type: mime
				});
				// 将blob转为文件
				blob.lastModifiedDate = new Date();
				blob.name = "file";
				let config = {
					//其他配置
				}
				this.Request(blob, config); //发起请求
			},
			Request(data, config) {
				axios.post('/url', data, config).then(res => {
					console.log("成功")
				}).catch(err => {
					console.log("失败")
				})
			}
		},

正确代码
仅是openCamera方法不同。测试发现ios 微信内置浏览器无法通过Audio或者Video获取视频时长,由于ios对视频压缩较好,9秒的视频大概1兆,所以只单独对ios的微信通过限制视频大小来限制时长。

openCamera(t) {
				// 判断浏览器
				let userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
				let MicroMessenger = userAgent.indexOf("MicroMessenger") > -1; //判断是否微信内置浏览器
				let isIPhone = userAgent.indexOf("iPhone") > -1; //判断是否是iPhone
				let i = t.target.files[0];
				let fileurl = URL.createObjectURL(i);
				let duration;//视频时长
				let that = this;
				let n = new FileReader();
				let fileSize = i.size / 1024 / 1024; //获取文件大小
				n.readAsDataURL(i);
				n.addEventListener("loadend", function() {
					let strContent = n.result;
					if (MicroMessenger && fileSize) {
						if (fileSize > 1) {
							console.log("文件大小" + fileSize);
							that.$message.error("视频时间过长,请重新录制");
						} else {
							that.base64ToFile(strContent);
						}
					} else {
						let audioElement = new Audio(fileurl);
						//经测试,发现audio也可获取视频的时长
						audioElement.addEventListener("loadedmetadata", function(_event) {
							duration = audioElement.duration;
							console.log("视频时长:" + duration);
							if (duration > 8) {
								that.$message.error("视频时间过长,请重新录制");
							} else {
								that.base64ToFile(strContent);
							}
						});
					}
				});
			},

以上为个人经验,如有错误请指出。

Logo

前往低代码交流专区

更多推荐