Skip to content

Latest commit

 

History

History
204 lines (178 loc) · 10.4 KB

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

File metadata and controls

204 lines (178 loc) · 10.4 KB

前言

产品又提需求了~ 前段时间在公司的项目中接到这样一个需求: 用户需要上传多个特定格式(只能是图片/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日 深圳 台风
划水一天