Vue组件放送之文件上传

栏目: JavaScript · 发布时间: 5年前

内容简介:文件上传组件是常见的 Web 组件。HTML 提供了 input file 原始上传组件,我们在此基础上利用各种 HTML5 特性来封装该组件,而不是通过内嵌一个隐藏 Flash 上传(古老的做法)。又因,利用了 vue 的 MVVM 和组件化的强大特性,这一切都变得简单轻松。先谈谈组件的需求——一般图片上传的场景较多,故该组件除了任意文件上传,还特意针对图片上传来开发:下面我们逐一分析需求的解决办法。

文件上传组件是常见的 Web 组件。HTML 提供了 input file 原始上传组件,我们在此基础上利用各种 HTML5 特性来封装该组件,而不是通过内嵌一个隐藏 Flash 上传(古老的做法)。又因,利用了 vue 的 MVVM 和组件化的强大特性,这一切都变得简单轻松。

先谈谈组件的需求——一般图片上传的场景较多,故该组件除了任意文件上传,还特意针对图片上传来开发:

  1. 可以无刷新上传可以无刷新上传
  2. 可以美化 input file 元素,允许自定义样式可以美化 input file 元素,允许自定义样式
  3. 可以预览本地图片
  4. 可以先压缩图片大小或者自定义分辨率
  5. 可以检测文件扩展名、文件大小、实际文件类型检测、图片分辨率大小
  6. 可以在弹出的文件选择框限制文件类型
  7. 可以显示上传进度
  8. 可以断点续传
  9. 在 iOS 上,有照片旋转不正确的问题,这个问题也必须得到解决。在 iOS 上,有照片旋转的问题,这个问题也必须得到解决。

下面我们逐一分析需求的解决办法。

XHR 2.0 文件上传

无刷新上传,实际上在 XHR 2 之前我一直使用 iframe 实现,原理是隐藏一个 ifame 并赋予 id,然后 form 表单 target 属性指向的就是那个 iframe id,这会形成是 ifame 上传的文件,表单的目的地是该 iframe,又因 iframe 是隐藏的,故能实现“无刷新”上传。

不过坑也不能避免的,一个表单是不允许嵌套另外一个表单的,所以我写这种 vue 组件时十分累,避免在同一个 iframe 中,要写大量 dom 控制语句,而且又要考虑多个上传组件的话,更麻烦了。

后来XHR 2.0 即 XmlHttpRequest 2.0 支持文件上传,问题迎刃而解。

var fd = new FormData();
if(this.$blob){ // File 类型不需要文件名,Blob 强制需要
	fd.append("file", this.$blob, this.$fileName);
} else 
	fd.append("file", this.$fileObj);

var xhr = new XMLHttpRequest(), self = this;
xhr.onreadystatechange = ajaxjs.xhr.callback.delegate(null, this.uploadOk_callback, 'json');
xhr.open("POST", this.action, true);
xhr.onprogress = function(evt) {
    var progress = 0;
    var p = ~~(evt.loaded * 1000 / evt.total);
    p = p / 10;
    
    if(progress !== p) {
    	progress = p;
    	console.log('progress: ', p);
    }
    self.progress = progress;
};
xhr.send(fd);

原理比较简单,就是 FormData 作为容器放置 file/blob 对象。注意 blob 必须指定文件名,否则后台会报错。

如上所见,XHR 包含了进度反馈的功能,也就是 progress 事件。于是把第9点需求也解决了。

美化上传按钮

如何美化就是样式 CSS 问题了。我们知道 label 标签有个特性,在设置了 for 属性后(该值是一个 id),就是点击标签文本会使得 id 所在的元素获得焦点,典型如 input 元素。有一个便捷不用设置 id 的方法就是 label 包含提示文字和 input 两者。

利用该方法,我们于是可以隐藏一个 input,然后通过 for/id 关联起来 label 与 input 元素,如下代码所示。

<label for="uploadInput_663">
	<div><div>+</div>点击选择图片</div>
</label>

<input type="file" id="uploadInput_663" accept="image/*" class="hide">

实际丑陋的 input 界面被隐藏了,我们可以随心所欲地美化 label 标签,如我制作的,

Vue组件放送之文件上传

但背后依然调用 input 的功能。

值得一提的的是, H5 可自定义弹出的文件选择框限制文件类型,如属性 accept=“image/” 表示只选择 图片 来上传,非常简单。

预览本地图片

我们知道 < img src=“xxx” /> 元素的图片可以是一个 url,或者 base64 编码的文本。图片还未上传到服务器,自然就没用所谓的 url,自然应该从 base64 方面“打主意”。H5 为我们提供 file 类型对象及其读取器 file reader,可以在浏览器本地读取到客户端计算机里面的图片,并转换为 base64 编码。先说说 File 对象,

// 当前 input file 元素触发的 onchange(e) 事件如下
this.$fileObj = e.target.files[0]; // 保留 File 对象 的引用。数组表示可以多选文件
this.$fileName = this.$fileObj.name; // 文件名
this.$fileType = this.$fileObj.type; // 文件类型,MIME
var size = this.$fileObj.size; // 文件大小

	// 文件头判别,看看是否为图片
	var imgHeader = {
		"jpeg" : "/9j/4",
		"gif" : "R0lGOD",
		"png" : "iVBORw"
	};
	
	for ( var i in imgHeader) {
		if (~imgBase64Str.indexOf(imgHeader[i])) {
			self.isExtName = true;
			return;
		}
	}
	
	self.errMsg = "亲,改了扩展名我还能认得你不是图片哦";

// 转换为 base64 字符串
var reader = new FileReader();
reader.onload = function(e) {
		var imgBase64Str = e.target.result; // 得到了图片的 base64 编码
		……
}
reader.readAsDataURL(file);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Visual Thinking

Visual Thinking

Colin Ware / Morgan Kaufmann / 2008-4-18 / USD 49.95

Increasingly, designers need to present information in ways that aid their audiences thinking process. Fortunately, results from the relatively new science of human visual perception provide valuable ......一起来看看 《Visual Thinking》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具