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

前言

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

一步一步来...

一.选择文件的HTML代码

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

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

image.png

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

            <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代码只是繁多,其实并不复杂。

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

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


image.png

当用户点击 + 号 会触发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中还要做一层判断
image.png

更多的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";
    }
  }
doc.png

excel.png

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日 深圳 台风
划水一天

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容