前言
产品又提需求了~
前段时间在公司的项目中接到这样一个需求:
用户需要上传多个特定格式(只能是图片/excal/word/txt)的文件存储至i服务器中,并可以进行查看。
当然,在这个需求中,我们前端要做的只是给用户一个选择文件的按钮,让用户能够选择本地文件,且筛选出特定格式的文件,并对用户选择的文件进行格式、大小的限制,然后将这些文件通过Ajax发送给后台就可以了。
一步一步来...
一.选择文件的HTML代码
博主项目使用的前端框架是angular4,所以其中可能使用了一些angular4的语法,不过前端框架之间都是异曲同工,相信一些简单的指令大家也能够猜到是什么意思。
首先给大家演示一下我所要做的功能
如下图所示,我在页面中设置了一个选择文件的 + 号按钮,用户点击 + 号可以按住Ctrl键进行多选文件,选择完毕之后,可以根据选择的文件类型的不同展示给用户不同的文件logo。
这边先直接贴上所有HTML的代码,再来进行详细
选择文件
+
-
{{data.fileName}}
-
1.1选择文件
上面的HTML代码只是繁多,其实并不复杂。
这俩个标签构成了选择文件的加号
这里我习惯在页面中写一个display为none的input标签,然后用其他标签来控制其样式,如在这里我就用了另一个class为addPic的div来显示选择文件的按钮效果。
样式这里就不贴了很简单。
当用户点击 + 号 会触发F_Open_dialog()
这个方法:
F_Open_dialog() {
document.getElementById("fileToUpload2").click();
}
它其实也就是触发了input的选择文件的事件
此时页面中就会出现本地文件夹供用户选择文件。
2.input详解
在上面的HTML代码中,最繁琐的就是input标签了,下面对其中的各种属性做一个说明:
type="file" --》类型为文件的input标签
multiple="multiple" --》 支持多选文件
(change)="onSelectByButton()" --》选择了文件触发onSelectByButton()方法
accept="image/*,text/plain, ......." --》用户能够看到的文件类型,定义了accept后,选择文件的类型会变为自定义文件,
也就是只让用户能够看到你给其限制的类型的文件,但若是用户选择了全部文件,还是可以选择到其他类型的文件,
所以我们在后面提交文件信息的时候在js中还要做一层判断
更多的accpet的内容信息可以自行度娘...
3.上传完文件之后的文件显示
可以看到在HTML代码中是定义了ul标签和li标签来盛放上传成功之后的文件的。
简单说一下angular4语法
*ngFor="let data of fileUploaded; let idx=index"
//类似vue中的v-for
//fileUploaded 数组,所有已经上传的文件的集合,在js中定义
//data 每一个文件
//let idx = index 定义变量idx 为 index下标,其实也就是为了简写index单词而已
可以看到我定义了俩种不同的li标签,一种是盛放上传成功的文件,一种盛放正在加载的图片
二.上传文件的js代码
在上面的讲解中,我们在用户选择了文件之后会触发一个onSelectByButton()
方法,该方法就是进行文件上传功能。
首先定义几个变量
...这里使用了TypeScript的写法,不过大家应该也能看懂
fileObj: any = [];//盛放所有要上传的文件
fileUploaded: any = [];//盛放已经上传成功的文件
loadingObj: any = [];//上传图片时的loading数组
loadingImage = { "url": "./assets/images/loading.gif" };//上传图片时的loading
然后就是设计上传的方法:
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()
方法:
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";
}
}
高清无码自己拿...
更多的矢量图可以到阿里巴巴矢量图标库中拿
前端应该都知道的iconfont
三.删除文件
在用户上传完了文件之后,可以点击右上角的删除图标删除要上传的文件
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
等,而不要采用以下的方式:
arr = ['one', 'two', 'three'];
arr[0] = 'newOne';
arr.length = 1;
采用上面的方式会使得视图层不能够及时的更新
之前在倔金上看到一篇有关不能更新数组视图的详解,还写了一些vue的小技巧,有需要的小伙可以移步:
你或许不知道Vue的这些小技巧
后语
2018年6月6日 深圳 台风
划水一天