使用element的upload组件实现一个完整的文件上传功能(下)

  

  本篇文章是《使用element的upload组件实现一个完整的文件上传功能(上)》的续篇。html

  话很少说,接着上一篇直接开始vue

一.功能完善—保存表格中每一列的文件列表状态

1.思路web

  保存表格中每一列的文件列表状态这个功能是什么意思呢,咱们先看下前面示例的效果。element-ui

  

  在上面这个操做中,咱们作了两件事:json

    1.给表格第一列的上传了一个附件图片数组

    2.点击表格第二列、第三列、第四列的上传按钮,分别查看这三列的附件列表浏览器

   那么最后的结果发现后三列的附件列表展现的都是第一列的附件图片,这个显然不符合正常的逻辑。仔细去看看咱们的代码而且思考一下,也很快能知道这个问题出现的缘由:咱们给<el-upload>的file-list属性绑定了attachList数据。attachList这个值初始是空数组,当咱们点击第一列的附件管理上传一张图片后,attachList数组就会增长一个元素。而全部上传按钮触发打开的弹框组件是同一个(咱们页面中只有一个<el-upload>元素),而弹框组件绑定的文件列表数据attachList也是公用的,所以就会出现上面的状况。到这里也很容易能想到思路去解决这个问题:不一样弹窗绑定的文件列表数据attachList分开保存。app

  那这个办法的言外之意就是须要在data中定义4个attachList,那定义四个数据,咱们就得定义写四个<el-dialog>分别去绑定这个四个数据。函数

  这个办法到是能解决问题,可是假如咱们的表格有100行数据呢,咱们难道要定义100个attachList,在写100个<el-dialog>吗?这显然就不现实了。post

  而后我换了个思路:定义一个数组去保存不一样的文件列表数据。这样在每次点击上传按钮时,将该列的文件列表数据赋值给另一个数据currentAttachList,而后咱们的<el-dialog>组件只须要绑定这个currentAttachList数据便可。这样就省事多了。

  最后就是保存不一样的文件列表数据的数组,这个要怎么定义呢。实际上也很简单,咱们能够将这个数据当作表格数据的一个属性定义在tableData中。

currentAttachList: [],
tableData: [{
  date: '2016-05-02',
  name: '王小虎',
  address: '上海市普陀区金沙江路',
  attachList:[]
}, {
  date: '2016-05-04',
  name: '王小虎',
  address: '上海市普陀区金沙江路',
  attachList:[]
}, {
  date: '2016-05-01',
  name: '王小虎',
  address: '上海市普陀区金沙江路',
  attachList:[]
}, {
  date: '2016-05-03',
  name: '王小虎',
  address: '上海市普陀区金沙江路',
  attachList:[]
}]

  tableData中的attachList就是咱们定义的文件列表数据

  数据定义好了以后,咱们继续下面的工做。

2.上传按钮的点击事件修改

  根据前面咱们写的一大堆的思路,能够知晓当咱们点击【附件管理】按钮时,须要作两件事:

    1.获取这一列表格数据中的附件列表,赋值给currentAttachList

    2.将控制弹框显示的dialogVisible设置为true,让弹框显示  

  那咱们以前写的点击【附件管理】按钮的事件处理程序以下:

<el-button size='small' type="primary" @click="dialogVisible = true">
  上传
  <i class="el-icon-upload el-icon--right"></i>
</el-button>          

  因此如今咱们须要将点击事件改成函数调用。

  在这以前呢,咱们说了须要获取上传按钮对应那一列的attachList数据,那咱们如何知道当前点击的上传按钮是属于表格的第几列呢?这个咱们使用插槽就能够实现了。

<el-table-column
  prop="attach"
  label="附件管理"
  width="180">
  <template slot-scope="scope">
    <!-- 上传按钮绑定click事件 -->
    <el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
      上传
      <i class="el-icon-upload el-icon--right"></i>
    </el-button>          
  </template>
</el-table-column>

  uploadBtnClick函数实现:

uploadBtnClick (index){
  // 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
  this.currentAttachList = this.tableData[index].attachList;
  // 将控制弹框显示的dialogVisible设置为true,让弹框显示
  this.dialogVisible = true;
}

  这两件事情完成后呢,记得将<el-dialog>的file-list绑定的数据改成currentAttachList。

  最后完整的App.vue组件代码以下

<template>
  <div id="app">
    <!-- element-ui Table表格组件 -->
    <el-table
        class="my-table"
        :data="tableData"
        stripe
        style="width:725px;">
        <el-table-column
          prop="date"
          label="日期"
          width="180">
        </el-table-column>
        <el-table-column
          prop="name"
          label="姓名"
          width="180">
        </el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="180">
        </el-table-column>
        <!-- 添加一列附件管理(文件上传) -->
        <el-table-column
          prop="attach"
          label="附件管理"
          width="180">
          <template slot-scope="scope">
            <!-- 上传按钮绑定click事件 -->
            <el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
              上传
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>          
          </template>
        </el-table-column>
      </el-table>
      <el-dialog
        title="附件管理"
        :visible.sync="dialogVisible"
        width="30%">
          <!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
          <el-upload
            class="upload-demo"
            drag
            action="https://jsonplaceholder.typicode.com/posts/"
            :file-list="currentAttachList">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
        </span>
      </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      // 添加属性,默认值为false,表示弹框不显示
      dialogVisible: false,
      // 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
      currentAttachList: [],
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }]
    } 
  },
  methods: {
    uploadBtnClick (index){
      // 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
      this.currentAttachList = this.tableData[index].attachList;
      // 将控制弹框显示的dialogVisible设置为true,让弹框显示
      this.dialogVisible = true;
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin: 50px 30px;
  text-align: center;
}
#app .el-dialog__header{
  background:#EBEEF5;
  border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
  text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
  width: 100%;
}
</style>
<style scoped>
#app .my-table{
  display: inline-block;
  border: 1px solid #EBEEF5;
}
</style>

  在浏览器中看下效果:

  

  仔细的看几遍这个效果,描述一下咱们的操做和结果:

    1.在第四列上传了一张图片,完成以后关闭弹窗

    2.点击第三列的上传按钮,获取tableData中第三列的attachList赋值给currentAttachList,此时第三列的attachList为空,因此currentAttachList也是空,因此第三列的附件列表展现为空,正常。(能够看到第三列的弹框点开后文件列表是一个从无到有的动画,是由于第四列上传了一个图片,currentAttachList包含一个元素,当点击第三列的上传按钮时将currentAttachList赋值为空,而element-ui提供的控件是包含动画的,因此就有了这个视觉上不太好的效果)

    然而,咱们最后还有一个操做:在查看完第三列的文件列表后,在返回点击第四列的附件管理按钮,查看第一个操做上传的文件列表。最后这个操做,咱们惊奇的发现前面上传在第四列的文件列表丢了。

  这个问题也比较好理解:上传完成后,须要将上传成功的文件信息保存到对应的那一列的attachList数组中。前面写的代码,咱们只读取了tableData中的attachList,在上传成功之后却没有将文件的信息保存到attachList里面,那么每次从新点击【附件管理】按钮,从tableData获取的attachList永远是空,在赋值给currentAttachList,文件列表就什么也不会展现。如今咱们能够接着修改代码了,须要修改的内容以下:

1.<el-upload>添加on-success钩子函数,当上传成功将本次上传的文件信息push到对应tableData.attachList

2.添加methods:uploadSuccess

关于这个uploadSuccess函数,它须要将上传成功的文件信息保存到对应的tableData.attachList,那咱们就须要知道当前是一列的按钮触发的弹框。这个问题就是以前在uploadBtnClick函数传递的参数index,因此咱们须要将这个index保存到vue的数据属性上,这样在uploadSuccess函数中也能用上。

data () {
    return {
          //当前点击打开弹框的按钮在表格中是那一列
      currentIndex: 0,
    }
}

  uploadBtnclick方法须要新增长下面的代码

uploadBtnClick (index){
  // 设置currentIndex
  this.currentIndex = index;
},

  uploadSuccess实现

 uploadSuccess(response, file, fileList){
   var currentIndex = this.currentIndex;
   this.tableData[currentIndex].attachList.push({
     'name':file.name
   });
 }

  最终完整的App.vue代码以下

<template>
  <div id="app">
    <!-- element-ui Table表格组件 -->
    <el-table
        class="my-table"
        :data="tableData"
        stripe
        style="width:725px;">
        <el-table-column
          prop="date"
          label="日期"
          width="180">
        </el-table-column>
        <el-table-column
          prop="name"
          label="姓名"
          width="180">
        </el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="180">
        </el-table-column>
        <!-- 添加一列附件管理(文件上传) -->
        <el-table-column
          prop="attach"
          label="附件管理"
          width="180">
          <template slot-scope="scope">
            <!-- 上传按钮绑定click事件 -->
            <el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
              上传
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>          
          </template>
        </el-table-column>
      </el-table>
      <el-dialog
        title="附件管理"
        :visible.sync="dialogVisible"
        width="30%">
          <!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
          <el-upload
            class="upload-demo"
            drag
            action="https://jsonplaceholder.typicode.com/posts/"
            :file-list="currentAttachList"
            :on-success="uploadSuccess">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
        </span>
      </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      // 添加属性,默认值为false,表示弹框不显示
      dialogVisible: false,
     // 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
      currentAttachList: [],
      //当前点击打开弹框的按钮是那一列
      currentIndex: 0,
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }]
    } 
  },
  methods: {
    uploadBtnClick (index){
      // 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
      this.currentAttachList = this.tableData[index].attachList;
      // 将控制弹框显示的dialogVisible设置为true,让弹框显示
      this.dialogVisible = true;
      // 设置currentIndex
      this.currentIndex = index;
    },
    uploadSuccess(response, file, fileList){
      var currentIndex = this.currentIndex;
      this.tableData[currentIndex].attachList.push({
        'name':file.name
      });
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin: 50px 30px;
  text-align: center;
}
#app .el-dialog__header{
  background:#EBEEF5;
  border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
  text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
  width: 100%;
}
</style>
<style scoped>
#app .my-table{
  display: inline-block;
  border: 1px solid #EBEEF5;
}
</style>

  浏览器查看结果:

  

  能够发现,前面的问题已经被咱们成功解决。

3.动画删除

如今呢,这个功能已经实现了。惟一很差的视觉效果就是文件列表的那个动画,咱们将这个动画删除。

<style>
#app .el-upload-list li{
  transition: none;
}

动画删除后的效果

   

  能够看到,如今的效果就正常了。

 

三.功能完善—删除附件

  删除文件这个功能,<el-upload>组件自己是支持的,只是在咱们这种多文件上传的状况中,还须要添加一下代码。

  咱们先看一下组件自己提供的这个删除功能

  

  咱们的操做顺序和结果以下

    ①点击第四列上传按钮

    ②成功上传两张图片

    ③删除第二张图片

    ④关闭弹窗,查看第四列文件列表,文件列表显示正常

    ⑤点击第三列上传按钮,文件列表为空显示正常

    ⑥在点击第四列的上传按钮,发现前面删除的那张图片依然显示在文件列表中。

  关于咱们删除第四列的一张图片后,在第⑥步点击查看发现图片依然存在的这个问题很好解释,咱们能够回头看一下uploadBtnclick函数的逻辑:

    每次点击上传按钮,将对应的tableData.attachList赋值给currentAttachList。

    而咱们删除的时候,并无删除对应的tableData.attachList中的数据,因此给currentAttachList的赋值操做致使文件列表展现的依然是以前的数据。

可是这里有一个疑惑的点就是第④个步骤:关闭弹窗,查看第四列文件列表,文件列表显示正常。这个就比较奇怪了,删除第二张图片后,按照前面咱们梳理的uploadBtnclick函数的逻辑,此时文件列表应该仍是会包含删除的那个文件。

关于这个问题,咱们在uploadBtnClick函数中添加一些打印信息:

uploadBtnClick (index){
    console.log('uploadBtnClick');
    console.log("this.tableData[index].attachList");
    console.log(this.tableData[index].attachList);
    // 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
    this.currentAttachList = this.tableData[index].attachList;
    console.log("this.currentAttachList");
    console.log(this.currentAttachList);
    // 将控制弹框显示的dialogVisible设置为true,让弹框显示
    this.dialogVisible = true;
    // 设置currentIndex
    this.currentIndex = index;
},

  而后截图看一下步骤④中的打印信息:

  

   能够看到,<el-upload>的file-list绑定的currentAttachList是包含两个元素(其中包含第③步删除的那个),可是文件列表却只显示了一个。

  enmmmmmm,这个地方比较费解。

  咱们先处理第六个步骤中删除出现的异常显示。根据咱们前面的梳理的逻辑,须要作两个修改

  methods添加handleRemove函数处理删除数据的功能

  <el-upload>添加on-remove钩子函数调用handleRemove

1.<el-upload>添加on-remove钩子函数调用handleRemove

 <el-upload
  class="upload-demo"
  drag
  action="https://jsonplaceholder.typicode.com/posts/"
  :on-remove="handleRemove"
  :file-list="currentAttachList"
  :on-success="uploadSuccess">
  <i class="el-icon-upload"></i>
    <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

2.methods添加handleRemove函数处理删除数据的功能

  关于handleRemove函数要实现的功能,前面咱们已经讲过:当删除一张图片后,删除对应的tableData.attachList中的数据。

  关于这个功能有两个办法能够实现:

    ①遍历tableData.attachList中的文件信息,将须要删除的文件删除。

    ②on-remove钩子函数在调用时有两个参数:file和fileList。

       file就是咱们当前操做的文件,对于删除操做,file就是当前删除文件的信息;

         fileList是操做完成后<el-upload>控件的的全部文件列表。

  所以,可直接将fileList赋值给tableData.attachList。

  咱们分别使用两种办法去实现。

  方法一:遍历tableData.attachList中的文件信息,将须要删除的文件删除

handleRemove(file, fileList){
  var currentIndex = this.currentIndex;
  var attachList = this.tableData[currentIndex].attachList;
  var tempList = [];
  for(var i = 0; i<attachList.length; i++){
    if(file.name != attachList[i].name){
      tempList.push(attachList[i]);
    }
  }
  this.tableData[currentIndex].attachList = tempList;
}

  方法二:直接将on-remove钩子函数的参数fileList赋值给tableData.attachList

handleRemove(file, fileList){
    var currentIndex = this.currentIndex;
    this.tableData[currentIndex].attachList = fileList;
}

  能够任意选择一种实现,效果均相同

  

四.功能完善—验证文件名是否重复

  element的多文件上传控件对重复的文件名并无任何限制。

  

  这个也不符合咱们实际的开发场景。所以咱们须要完善这个功能。

  查看element文档,咱们能够看到一个before-upload钩子函数

  

   所以咱们能够给<el-upload>控件添加before-upload钩子函数,在上传文件以前去判断文件是否重名,如有重名则阻止上传。

1.给<el-upload>控件添加before-upload钩子函数

 

 <!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
<el-upload
   class="upload-demo"
   drag
   action="https://jsonplaceholder.typicode.com/posts/"
   :on-remove="handleRemove"
   :file-list="currentAttachList"
   :on-success="uploadSuccess"
   :before-upload="beforeUpload">
  <i class="el-icon-upload"></i>
  <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

 

2.methods定义beforeUpload函数

beforeUpload(file){
  var currentIndex = this.currentIndex;
  //首先须要获取当前已经上传的文件列表
  var list = this.tableData[currentIndex].attachList;
  //循环文件列表判断是否有重复的文件
  for(var i = 0;i<list.length;i++){
    if(list[i].name == file.name){
      this.$message.error(file.name + '文件名重复');
      //记得必定要返回false,不然控件继续会执行上传操做
      return false;
    }
  }
}

  如今看下效果:

  

  能够看到当文件名称重复时,会有一个错误提示而且成功阻止了这个重复文件的上传。

  然而,当咱们在此查看文件列表时,发现以前存在的文件在列表中丢失了。

  这个缘由是为啥呢?由于当bfeore-upload返回false以后,该组件会默认执行before-remove和on-remove这个两个钩子函数,咱们在使用这个控件的时候只添加了on-remove这个钩子函数,为了证明这个默认行为,咱们把before-remove这个钩子函数加上,而且在添加一些打印信息。

  添加before-remove钩子函数

<el-upload
  class="upload-demo"
  drag
  action="https://jsonplaceholder.typicode.com/posts/"
  :on-remove="handleRemove"
  :before-remove="beforeRemove"
  :file-list="currentAttachList"
  :on-success="uploadSuccess"
  :before-upload="beforeUpload">
  <i class="el-icon-upload"></i>
  <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

  methods添加beforeRemove和一些打印信息

beforeRemove(file, fileList){
  console.log('我是before-remove钩子函数,我被调用了');
},
 handleRemove(file, fileList){
   console.log('我是on-remove钩子函数,我被调用了');
   var currentIndex = this.currentIndex;
   var attachList = this.tableData[currentIndex].attachList;
   var tempList = [];
   for(var i = 0; i<attachList.length; i++){
     if(file.name != attachList[i].name){
       tempList.push(attachList[i]);
     }
   }
   this.tableData[currentIndex].attachList = tempList;
 },

 

  而后就刚刚上传重复文件的那个操做咱们看下打印信息

  

 

  能够看到咱们前面的说法已经被证明了。

  同时,在深刻一步思考一下,由于阻止上传重复的文件名,致使on-remove钩子函数被调用删除了对应tableData.attachList中的数据,因此当咱们在此点击查看文件列表时【皇阿玛问号.jpg】已经不存在了。

  那如何解决这个问题呢?

  首先咱们先将before-remove这个钩子函数完善一下:删除前给用户提示确认是否删除

beforeRemove(file, fileList){
  return this.$confirm('此操做将永久删除' + file.name +'文件, 是否继续?');
},

  而后,解决这个问题的关键是:当before-upload返回false后,不执行before-remove和on-remove这两个钩子函数里面的逻辑。

  那咱们看一下关于before-remove钩子函数的文档

  

  能够看到,该钩子函数能够经过返回false中止删除,便可以阻止on-remove函数的调用。

  因此咱们将思路转到before-remove函数,只要能在before-remove里面作出一些判断,在上传重复的文件后使函数返回false。

  那么如今须要作的就是在before-upload中得知上传了重复文件后,设置isRepeat标志值为true,在before-remove判断若是isRepeat这个标志值为true,就令该钩子函数返回false阻止on-remove函数的调用。

data () {
  return {
    //是否包含重复的文件名称,默认不包含值为false
    isRepeat: false 
  } 
}, 
methods: {
  beforeRemove(file, fileList){
    if(this.isRepeat == false){
      return this.$confirm('此操做将永久删除' + file.name +'文件, 是否继续?');
    }else{
      // 这个逻辑表示包含重复的文件,这按照文档返回false可阻止文件继续上传
      return false;
    }
  },
  beforeUpload(file){
    var currentIndex = this.currentIndex;
    //首先须要获取当前已经上传的文件列表
    var list = this.tableData[currentIndex].attachList;
    //循环文件列表判断是否有重复的文件
    for(var i = 0;i<list.length;i++){
      if(list[i].name == file.name){
        this.$message.error(file.name + '文件名重复');
        //添加逻辑:得知上传了重复文件后,设置一个标志值为true,提供给beforeRemove函数使用
        this.isRepeat = true;
        //记得必定要返回false,不然控件继续会执行上传操做
        return false;
      }
    }
  }
}

  而后咱们看下效果:

  

  这个结果看到以后有些吐血。

  虽然当有重复文件上传时有了错误提示,可是这个重复发文件名却展现在了文件列表中。查看了打印信息,发现并无调用on-remove钩子函数。

  (这个文件上传控件这么鸡肋吗?仍是我用法有误?)

  没办法,也不知道啥缘由,我只能在想一想办法。

  在转了转脑子,因而想尝试把before-remove中 else{ return false;}逻辑删除,这样当文件名称重复后,会自动调用on-remove钩子函数,咱们把对isRepeat数据的判断加在on-remove钩子函数中去阻止删除操做。

beforeRemove(file, fileList){
  if(this.isRepeat == false){
    return this.$confirm('此操做将永久删除' + file.name +'文件, 是否继续?');
  }
},
handleRemove(file, fileList){
  console.log('我是on-remove钩子函数,我被调用了');
  if(this.isRepeat == false){
    var currentIndex = this.currentIndex;
    var attachList = this.tableData[currentIndex].attachList;
    var tempList = [];
    for(var i = 0; i<attachList.length; i++){
      if(file.name != attachList[i].name){
        tempList.push(attachList[i]);
      }
    }
    this.tableData[currentIndex].attachList = tempList;
  }
 },  

  再看下效果:

  

  如今看起来这个效果是正常了,重复的文件没有上传也没有展现到文件列表中,在此点击查看也显示正常。

  可是呢,还有最后一个问题,保证是最后一个问题了:

    由于当文件重复后,isRepeat设置为了true,以后在没有地方修改这个数据,那么一个重复图片上传后,咱们操做删除文件,此时isRepeat设置为true,按照逻辑before-remove中的删除提示不会执行,on-remove中的删除逻辑也不会执行。

  因此呢,咱们还须要在上传重复图片后,将this.isRepeat还原为false,那么咱们将代码添加到on-remove函数中便可。

handleRemove(file, fileList){
  console.log('我是on-remove钩子函数,我被调用了');
  if(this.isRepeat == false){
    var currentIndex = this.currentIndex;
    var attachList = this.tableData[currentIndex].attachList;
    var tempList = [];
    for(var i = 0; i<attachList.length; i++){
      if(file.name != attachList[i].name){
        tempList.push(attachList[i]);
      }
    }
    this.tableData[currentIndex].attachList = tempList;
  }else{
    this.isRepeat = false;
  }
 },  

  最后咱们将打印信息删除,贴上完整的代码

src/App.vue

<template>
  <div id="app">
    <!-- element-ui Table表格组件 -->
    <el-table
        class="my-table"
        :data="tableData"
        stripe
        style="width:725px;">
        <el-table-column
          prop="date"
          label="日期"
          width="180">
        </el-table-column>
        <el-table-column
          prop="name"
          label="姓名"
          width="180">
        </el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="180">
        </el-table-column>
        <!-- 添加一列附件管理(文件上传) -->
        <el-table-column
          prop="attach"
          label="附件管理"
          width="180">
          <template slot-scope="scope">
            <!-- 上传按钮绑定click事件 -->
            <el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
              上传
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>          
          </template>
        </el-table-column>
      </el-table>
      <el-dialog
        title="附件管理"
        :visible.sync="dialogVisible"
        width="30%">
          <!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
          <el-upload
            class="upload-demo"
            drag
            action="https://jsonplaceholder.typicode.com/posts/"
            :on-remove="handleRemove"
            :before-remove="beforeRemove"
            :file-list="currentAttachList"
            :on-success="uploadSuccess"
            :before-upload="beforeUpload">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
        </span>
      </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      // 添加属性,默认值为false,表示弹框不显示
      dialogVisible: false,
     // 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
      currentAttachList: [],
      //当前点击打开弹框的按钮在表格中是那一列
      currentIndex: 0,
      //是否包含重复的文件名称,默认不包含值为false
      isRepeat: false,
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路',
        attachList:[]
      }]
    } 
  },
  methods: {
    uploadBtnClick (index){
      // 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
      this.currentAttachList = this.tableData[index].attachList;
      // 将控制弹框显示的dialogVisible设置为true,让弹框显示
      this.dialogVisible = true;
      // 设置currentIndex
      this.currentIndex = index;
    },
    uploadSuccess(response, file, fileList){
      var currentIndex = this.currentIndex;
      this.tableData[currentIndex].attachList.push({
        'name':file.name
      });
    },
    beforeRemove(file, fileList){
      if(this.isRepeat == false){
        return this.$confirm('此操做将永久删除' + file.name +'文件, 是否继续?');
      }
    },
    handleRemove(file, fileList){
      if(this.isRepeat == false){
        var currentIndex = this.currentIndex;
        var attachList = this.tableData[currentIndex].attachList;
        var tempList = [];
        for(var i = 0; i<attachList.length; i++){
          if(file.name != attachList[i].name){
            tempList.push(attachList[i]);
          }
        }
        this.tableData[currentIndex].attachList = tempList;
      }else{
        this.isRepeat = false;
      }
    },
    beforeUpload(file){
      var currentIndex = this.currentIndex;
      //首先须要获取当前已经上传的文件列表
      var list = this.tableData[currentIndex].attachList;
      //循环文件列表判断是否有重复的文件
      for(var i = 0;i<list.length;i++){
        if(list[i].name == file.name){
          this.$message.error(file.name + '文件名重复');
          //添加逻辑:得知上传了重复文件后,设置一个标志值为true,提供给beforeRemove函数使用
          this.isRepeat = true;
          //记得必定要返回false,不然控件继续会执行上传操做
          return false;
        }
      }
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin: 50px 30px;
  text-align: center;
}
#app .el-dialog__header{
  background:#EBEEF5;
  border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
  text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
  width: 100%;
}
#app .el-upload-list li{
  transition: none;
}
</style>
<style scoped>
#app .my-table{
  display: inline-block;
  border: 1px solid #EBEEF5;
}
</style>

 

  最后在来操做一波

  

   

五.总结

  到此,《使用element的upload组件实现一个完整的文件上传功能》完成,该功能是结合前段时间在实际项目开发中作的一个功能,在这里单独拿出来总结。

  在整个实践过程当中,我的感受element的upload组件,对多文件的上传功能仍是不太友好,两个至今尚未探究明白的问题,在文中也以红色字体标出。

  这两个问题虽然看着不影响什么,但内心老是有些不踏实。

 


相关文章
相关标签/搜索