前端上传文件及进行文件类型大小限制

前言
产品又提需求了~
前段时间在公司的项目中接到这样一个需求:
用户需要上传多个特定格式(只能是图片/excal/word/txt)的文件存储至i服务器中,并可以进行查看。
当然,在这个需求中,我们前端要做的只是给用户一个选择文件的按钮,让用户能够选择本地文件,且筛选出特定格式的文件,并对用户选择的文件进行格式、大小的限制,然后将这些文件通过Ajax发送给后台就可以了。

一步一步来…

一.选择文件的HTML代码

博主项目使用的前端框架是angular4,所以其中可能使用了一些angular4的语法,不过前端框架之间都是异曲同工,相信一些简单的指令大家也能够猜到是什么意思。

首先给大家演示一下我所要做的功能
如下图所示,我在页面中设置了一个选择文件的 + 号按钮,用户点击 + 号可以按住Ctrl键进行多选文件,选择完毕之后,可以根据选择的文件类型的不同展示给用户不同的文件logo。

image.png

这边先直接贴上所有HTML的代码,再来进行详细

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div class="ui-g-3" style="width: 100%;">
<div class="selectPic">
选择文件
</div>
<div class="addPic" (click)="F_Open_dialog()">
<span class="plusSign">+</span>
</div>
<input type="file" name="fileToUpload2" id="fileToUpload2" (change)="onSelectByButton()"
multiple="multiple" style="display:none" accept="image/*,text/plain ,
application/vnd.ms-excel ,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
application/msword, application/msexcel,
application/vnd.openxmlformats-officedocument.wordprocessingml.document,
application/vnd.openxmlformats-officedocument.wordprocessingml.template"/>
<ul style="float:left;" id="deal" class="picList">
<li class="fl text_center margin_left_5" *ngFor="let data of fileUploaded; let idx=index">
<!--上传的文件不同的类型显示不同的logo-->
<img width="70" height="70" src="{{data.fileUrl}}" />
<!--右上角的删除图片-->
<span class="fa fa-fw fa-close" (click)="deletePicture(idx)" style="float: right;"></span>
<!--文件名-->
<p style="display: block" [title]="data.fileName" class="fileName">{{data.fileName}}</p>
</li>
<!--上传文件时的loading-->
<li class="fl" *ngFor="let dataLoading of loadingObj" style="float:left;">
<img width="70" height="70" src="{{dataLoading.url}}" />
</li>
</ul>
</div>

1.1选择文件

上面的HTML代码只是繁多,其实并不复杂。

1
2
<div class="addPic"></div>
<input type="file" style="display: none" />

这俩个标签构成了选择文件的加号
这里我习惯在页面中写一个display为none的input标签,然后用其他标签来控制其样式,如在这里我就用了另一个class为addPic的div来显示选择文件的按钮效果。
样式这里就不贴了很简单。
image.png

当用户点击 + 号 会触发F_Open_dialog()这个方法:

1
2
3
F_Open_dialog() {
document.getElementById("fileToUpload2").click();
}

它其实也就是触发了input的选择文件的事件

此时页面中就会出现本地文件夹供用户选择文件。

2.input详解

在上面的HTML代码中,最繁琐的就是input标签了,下面对其中的各种属性做一个说明:

1
2
3
4
5
6
type="file" --》类型为文件的input标签
multiple="multiple" --》 支持多选文件
(change)="onSelectByButton()" --》选择了文件触发onSelectByButton()方法
accept="image/*,text/plain, ......." --》用户能够看到的文件类型,定义了accept后,选择文件的类型会变为自定义文件,
也就是只让用户能够看到你给其限制的类型的文件,但若是用户选择了全部文件,还是可以选择到其他类型的文件,
所以我们在后面提交文件信息的时候在js中还要做一层判断

image.png

更多的accpet的内容信息可以自行度娘…

3.上传完文件之后的文件显示

可以看到在HTML代码中是定义了ul标签和li标签来盛放上传成功之后的文件的。
简单说一下angular4语法

1
2
3
4
5
*ngFor="let data of fileUploaded; let idx=index"   
//类似vue中的v-for
//fileUploaded 数组,所有已经上传的文件的集合,在js中定义
//data 每一个文件
//let idx = index 定义变量idx 为 index下标,其实也就是为了简写index单词而已

可以看到我定义了俩种不同的li标签,一种是盛放上传成功的文件,一种盛放正在加载的图片

###二.上传文件的js代码

在上面的讲解中,我们在用户选择了文件之后会触发一个onSelectByButton()方法,该方法就是进行文件上传功能。
首先定义几个变量
…这里使用了TypeScript的写法,不过大家应该也能看懂

1
2
3
4
fileObj: any = [];//盛放所有要上传的文件
fileUploaded: any = [];//盛放已经上传成功的文件
loadingObj: any = [];//上传图片时的loading数组
loadingImage = { "url": "./assets/images/loading.gif" };//上传图片时的loading

然后就是设计上传的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
onSelectByButton() {//选择文件
let fileObjSelect = document.getElementById("fileToUpload2")["files"];
let reg = /\/(?:jpeg|png|jpg)|\-officedocument\.*|text\/\.*|vnd\.ms\-excel/i;//判断文件类型是不是图片/txt/Word文档格式/Excel格式
let postfixReg = /.+\./;//获取文件名后缀的正则表达式
let formdata = new FormData();

/*限制用户选择的文件类型和大小*/
for (var i = 0; i < fileObjSelect.length; i++) {//遍历所有选择的文件
let file = fileObjSelect[i];
if (reg.test(file.type)) {//判断文件类型
if (file.size > 0 && file.size <= 10485760) {//判断文件大小
this.fileObj.push(file);//将要上传的文件推进数组中
this.loadingObj.push(this.loadingImage);//推进一个加载loading的图片
formdata.append("file", file);
} else {
this.growl('error', '错误信息', '上传的文件不能小于0kb且不能大于10mb!');//growl是自己封装的一个错误提示的方法
}
} else {
this.growl('error', '错误信息', '请选择excel、 word、 txt、 jpg、 png格式的文件!');
}
}

/*这里是我自己封装的一个post请求的方法,第一个参数为所有要上传的文件,第二个为接口地址(后台会给你)*/
this.httpService.httpPostAFile(formdata, "/file/setAttachment").then(data => {

// data就是你发送post请求之后后台返回给你的数据,其中可能包含所有你上传的文件的信息
if (data != null && data["success"] && data['data']) {
data.data.forEach(dataFile => {//遍历文件数组
let postfix = dataFile['fileName'].replace(postfixReg, "");//获取到每一个文件的后缀
if (postfix === 'jpeg' || postfix === 'png' || postfix === 'jpg') {
//这里拿到的是图片文件,你可以在这里做一些事情
} else {
//这里拿到的是所有非图片的文件
//我在这里定义了一个方法,用于对不同类型的文件显示给用户不同的logo
dataFile['fileUrl'] = this.setFileUrl(postfix); //dataFile是每一个文件,我定义一个属性fileUrl用于显示文件logo
}
this.fileUploaded.push(dataFile);//将上传成功的文件推进数组
});
this.loadingObj = [];//清空加载loading
}
})
}

贴一下上面用到的setFileUrl()方法:

1
2
3
4
5
6
7
8
9
10
11
setFileUrl(postfix) {//设置文件在列表中的显示
if (postfix === 'docx' || postfix === 'docm' || postfix === 'dotx' || postfix === 'dotm') {//Word文档
return "./assets/images/member/doc.png";
} else if (postfix === 'xls' || postfix === 'xlsx'
|| postfix === 'xlsm' || postfix === 'xltx' || postfix === 'xltm'
|| postfix === 'xlsb' || postfix === 'xlam') {
return "./assets/images/member/excel.png";
} else if (postfix === 'txt') {
return "./assets/images/member/txt.png";
}
}

doc.png
excel.png
txt.png

高清无码自己拿…
更多的矢量图可以到阿里巴巴矢量图标库中拿
前端应该都知道的iconfont

三.删除文件

在用户上传完了文件之后,可以点击右上角的删除图标删除要上传的文件

1
2
3
4
5
6
7
deletePicture(idx) {//删除文件
var oBox = document.getElementById('deal');
var aSpan = oBox.getElementsByTagName("span");
oBox.removeChild(aSpan[idx].parentNode);
this.fileUploaded.splice(idx, 1);
this.fileObj.splice(idx, 1);
}

不管是在vue还是在angular中,在对数组或者对象进行操作时,都尽量使用数组/对象自带的一些方法,如数组中的splice slice sort push pop等,而不要采用以下的方式:

1
2
3
4
arr = ['one', 'two', 'three'];

arr[0] = 'newOne';
arr.length = 1;

采用上面的方式会使得视图层不能够及时的更新
之前在倔金上看到一篇有关不能更新数组视图的详解,还写了一些vue的小技巧,有需要的小伙可以移步:
你或许不知道Vue的这些小技巧

后语

2018年6月6日 深圳 台风
划水一天

评论