zoukankan      html  css  js  c++  java
  • 使用element的upload组件实现一个完整的文件上传功能(下)

      

      

    作者:小土豆biubiubiu

    博客园:www.cnblogs.com/HouJiao/

    掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d

    简书:https://www.jianshu.com/u/cb1c3884e6d5

    微信公众号:土豆妈的碎碎念(扫码关注,一起吸猫,一起听故事,一起学习前端技术)

    码字不易,点赞鼓励哟~

     

      

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

      话不多说,接着上一篇直接开始

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

    1.思路

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

      

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

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

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

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

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

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

      然后我换了个思路:定义一个数组去保存不同的文件列表数据。这样在每次点击上传按钮时,将该列的文件列表数据赋值给另外一个数据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="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="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="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组件,对多文件的上传功能还是不太友好,两个至今还没有探究明白的问题,在文中也以红色字体标出。

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


      

  • 相关阅读:
    iOS边练边学--tableView的批量操作
    iOS边练边学--简单的数据操作(增、删、改),左滑动删除和弹窗
    iOS边练边学--自定义非等高的cell
    iOS边练边学--自定义等高的cell
    iOS边练边学--UITableViewCell的常见属性设置
    iOS边练边学--UITableView性能优化之三种方式循环利用
    iOS边练边学--介绍布局的三种方法
    c++ 函数的函数声明
    using namespace std
    java.lang.ExceptionInInitializerError
  • 原文地址:https://www.cnblogs.com/HouJiao/p/12125313.html
Copyright © 2011-2022 走看看