精华内容
下载资源
问答
  • vue 批量上传文件

    2021-01-11 17:21:50
    业务背景:一次性批量上传多个文件,只请求一次接口,则手动提交到后台 简单说明一个实现思路: 1.前端vue统一处理多个文件保存到formData对象中,请求后台接口 2.后台接口使用HttpServletRequest 进行接收,可转化成...

    业务背景:一次性批量上传多个文件,只请求一次接口,则手动提交到后台

    简单说明一个实现思路:

    1. 前端vue统一处理多个文件保存到formData对象中,请求后台接口
    2. 后台接口使用HttpServletRequest 进行接收,可转化成MultipartHttpServletRequest对象接收前端formData对象
    //前端使用的UI组件是Ant Design of Vue的upload组件
    <template>
      <div class="clearfix">
        <a-upload
          :multiple="true"
          :before-upload="beforeUpload"
          :list-type="listType"
          :file-list="fileList"
          @preview="handlePreview"
          @change="handleChange"
          @download="handleDownload"
        >
          <div v-if="isMore">
            <a-icon type="plus" />
            <div class="ant-upload-text">文件上传</div>
          </div>
          <div v-if="!isMore && fileList.length < 1">
            <a-icon type="plus" />
            <div class="ant-upload-text">文件上传</div>
          </div>
        </a-upload>
        <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
          <img alt="example" style="width: 100%" :src="previewImage" />
        </a-modal>
      </div>
    </template>
    
    
    JS的核心代码:
    handleUpload() {
          const { fileList } = this
          if (fileList.length > 0) {
            var notUploaded = []
            var uploaded = []
            fileList.forEach((item) => {
              if (item.status && item.status === 'done') {
                uploaded.push(item.url)
              } else {
                notUploaded.push(item)
              }
            })
            let formData = new FormData()
            notUploaded.forEach((file, index) => {
              //所有文件保存在formData中
              formData.append(`file${index}`, file.originFileObj)
            })
            console.log('formData', JSON.stringify(formData))
            //请求批量上传接口
            batchUploadFile(formData, this.targetS).then((res) => {
              if (res.success) {
                console.log('res', JSON.stringify(res))
              } else {
                this.$message.error('图片上传失败,请重新上传')
              }
            })
            // return
            //this.$emit('loadImgUrl', this.loadImgUrl.join(','))
            //this.fileList = []
          } else {
            // 如果没有图片则返回空
            //this.$emit('loadImgUrl', '')
            //this.fileList = []
          }
        },
    
    后台代码:
    
        @ApiOperation(value = "批量文件上传(最多同时上传5个文件)", notes = "批量文件上传")
        @PostMapping("/batchUploadFile/{filePath}")
        public Result<?> batchUploadFile(@ApiParam(value = "自定义上传文件的路径")
                                         @PathVariable("filePath") String filePath,
                                         HttpServletRequest request) throws Exception {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
            if (fileMap.isEmpty()) {
                return Result.error("上传文件不能为空");
            }
            if (fileMap.size() > 5) {
                return Result.error("批量上传文件数量不能超过5个文件");
            }
            List<Map<String, Object>> mapList = ftpUtils.batchUploadFile(fileMap, filePath);
            return Result.OK(mapList);
        }
    

    注意:以上代码部分功能不完全只能作为参考,重点是实现思路
    1.前端是如何组装参数

      let formData = new FormData()
            notUploaded.forEach((file, index) => {
              //所有文件保存在formData中
              formData.append(`file${index}`, file.originFileObj) //核心代码
            })
    

    2.后台使用MultipartHttpServletRequest对象进行接受

      MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
    

    前端参数格式:
    在这里插入图片描述

    在这里插入图片描述

    请求结果:
    在这里插入图片描述

    展开全文
  • 一、文件上传 记一次文件上传文件下载,写的比较仓促,就记录了代码过程,其他没有详细解释,只为记录自己知识积累的过程。 1、单文件上传 HTML部分: <el-row v-for="(item,index) in DebugfileList"> &...

    一、文件上传

    记一次文件上传和文件下载,写的比较仓促,就记录了代码过程,其他没有详细解释,只为记录自己知识积累的过程。
    1、单文件上传

    HTML部分:

     <el-row v-for="(item,index) in DebugfileList">
            <el-col :span="10"><span>{{item.name}}</span></el-col>
            <el-col :span="14">
              <el-upload 
                class="upload-demo"
                action="#" 
                :data="{name:item.businessType}" 
                :on-remove="handleRemove"
                :before-remove="beforeRemove" 
                :limit="1" 
                :on-exceed="handleExceed" 
                :file-list="item.fileList"
                :http-request="handelUploadDebugfile" 
                style="display:flex;flex-direction:row;">
                <el-button size="small" type="primary" icon="el-icon-document-add">选取文件</el-button>
              </el-upload>
            </el-col>
            </el-upload>
          </el-row>
    

    JS部分:

     // 单文件调试附件上传
          handelUploadDebugfile(e) {
            let file = e.file;
            let form = new FormData()
            let maxType = '1';
            let businessType = e.data.name;
            form.append('files', e.file);
            uploadfile(form, this.orderId, maxType, businessType).then(data => {
              this.getDeFilesTableData()
            })
          },//这里传了四个参数,files,orderId,maxType,businessType
    
    2、多文件上传

    HTML部分:

     <el-dialog title="上传文件" :visible.sync="dialogFile" width="50%">
          <div class="item list">
            <div>
              <el-row>
                <el-col :span="3"><span> 文件类型选择:</span>
                </el-col>
                <el-col :span="5">
                  <el-select v-model="fileTypevalue" placeholder="请选择文件类型">
                    <el-option v-for="item in options" :key="item.value" :label="item.name" :value="item.value">
                    </el-option>
                  </el-select>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
              <el-row>
                <el-col :span="3"><span> 上传文件:</span></el-col>
                <el-col :span="5">
                  <el-upload 
                    action="#" 
                    ref="upload"  
                    :before-upload="beforeupload" 
                    :on-preview="handlePreview" 
                    :on-remove="handleRemove" 
                    multiple
                    :file-list="mutiFileList" 
                    :auto-upload="false" 
                    :http-request="mutiFilesUpload">
                    <el-button slot="trigger" size="small" type="primary" icon="el-icon-folder-add">上传附件</el-button>
                  </el-upload>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
            </div>
          </div>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogFile = false">取 消</el-button>
            <el-button type="primary" icon="el-icon-upload" @click="submitFiles">上传到服务器</el-button>
          </span>
        </el-dialog>
    

    JS部分:

    
          // 多文件附件上传到服务器
          mutiFilesUpload(e) {
            this.Filesform.append('files', e.file)
          },
          // 多文件附件上传到服务器
          submitFiles() {
              this.Filesform = new FormData()
              this.$refs.upload.submit()
              let maxType = '2';
              let businessType = this.fileTypevalue;
              let form = this.Filesform
            if (this.fileTypevalue != '' && this.flag) {
              uploadfile(form, this.orderId, maxType, businessType).then(data => {
                this.dialogFile = false
                this.fileTypevalue = ''
                this.$refs.upload.clearFiles()
                this.flag=false
                this.getFilesTableData()
              })
            } else {
              this.$notify({
                title: '警告',
                message: '请选择文件类型或文件',
                type: 'warning'
              });
            }
          },
    

    一、文件下载

    HTML部分:

     <el-button size="mini" type="warning" icon="el-icon-download" @click="download(row)">下载</el-button>
    

    JS部分:

     download(row) {
            let id = row.id
            var elemIF = document.createElement('iframe');
            elemIF.src = '/api/produce/workFileInfo/downloadFile?id=' + id;
            elemIF.style.display = 'none';
            document.body.appendChild(elemIF);
          },
    

    附:整个页面代码

    <template>
        <div class="main">
        <!-- 单文件调试附件 -->
        <div class="item">
          <el-row v-for="(item,index) in DebugfileList">
            <el-col :span="10"><span>{{item.name}}</span></el-col>
            <el-col :span="14">
              <el-upload 
                class="upload-demo"
                action="#" 
                :data="{name:item.businessType}" 
                :on-remove="handleRemove"
                :before-remove="beforeRemove" 
                :limit="1" 
                :on-exceed="handleExceed" 
                :file-list="item.fileList"
                :http-request="handelUploadDebugfile" 
                style="display:flex;flex-direction:row;">
                <el-button size="small" type="primary" icon="el-icon-document-add">选取文件</el-button>
              </el-upload>
            </el-col>
            </el-upload>
          </el-row>
          <el-button type="primary" icon="el-icon-folder-add" @click="dialogdebugFile=true">点击上传文件</el-button>
          <!-- 调试附件表格-->
          <el-table :data="DeFilesTableData" border fit highlight-current-row style="width: 100%;">
            <el-table-column label="文件名称" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.fileName }}</span>
              </template>
            </el-table-column>
            <el-table-column label="类型" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.businessType }}</span>
              </template>
            </el-table-column>
            <el-table-column label="时间" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.createTime }}</span>
              </template>
            </el-table-column>
    
            <el-table-column label="操作" align="center" width="230" class-name="small-padding " fixed="right">
              <template slot-scope="{row}">
                <el-button type="danger" size="mini" icon="el-icon-delete" @click="Delete(row)">删除</el-button>
                <el-button size="mini" type="warning" icon="el-icon-download" @click="download(row)">下载</el-button>
              </template>
            </el-table-column>
          </el-table>
          <pagination 
            :pageSizes="pageSizes" 
            v-show="detotal>0" 
            :total="detotal" 
            :auto-scroll="false"
            :page.sync="listDeFileQuery.page" 
            :limit.sync="listDeFileQuery.limit" 
            @pagination="getDeFilesTableData" />
        </div>
        <div style="border-bottom:1px solid #ccc;height:5px;"></div>
    
        <!-- 单文件附件 -->
        <div class="item">
          <el-row v-for="(item,index) in fileList">
            <el-col :span="12"><span>{{item.name}}</span></el-col>
            <el-col :span="12">
              <el-upload 
               action="#" 
               class="upload-demo" 
               :on-remove="handleRemove" 
               :before-remove="beforeRemove" 
               :limit="1"
               :data="{name:item.businessType}" 
               :http-request="handelUploadfile" 
               :on-exceed="handleExceed"
               :file-list="item.fileList" 
               style="display:flex;flex-direction:row;">
                <el-button size="small" type="primary" icon="el-icon-document-add">选取文件</el-button>
              </el-upload>
            </el-col>
            </el-upload>
          </el-row>
          <el-button type="primary" icon="el-icon-folder-add" @click="dialogFile=true">点击上传文件</el-button>
          <!-- 附件表格 -->
          <el-table :data="filesTableData" border fit highlight-current-row style="width: 100%;">
            <el-table-column label="文件名称" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.fileName }}</span>
              </template>
            </el-table-column>
            <el-table-column label="类型" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.businessType }}</span>
              </template>
            </el-table-column>
            <el-table-column label="时间" min-width="150px" align="center">
              <template slot-scope="{row}">
                <span>{{ row.createTime }}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="230" class-name="small-padding " fixed="right">
              <template slot-scope="{row}">
                <el-button type="danger" size="mini" icon="el-icon-delete" @click="Delete(row)">删除</el-button>
                <el-button size="mini" type="warning" icon="el-icon-download" @click="download(row)">下载</el-button>
              </template>
            </el-table-column>
          </el-table>
          <pagination 
            :pageSizes="pageSizes" 
            v-show="filetotal>0" 
            :total="filetotal" 
            :auto-scroll="false"
            :page.sync="listFileQuery.page" 
            :limit.sync="listFileQuery.limit" 
            @pagination="getFilesTableData" />
        </div>
    
        <!-- 调试附件上传弹出框 -->
        <el-dialog title="上传文件" :visible.sync="dialogdebugFile" width="50%">
          <div class="item list">
            <div>
              <el-row>
                <el-col :span="3"><span> 文件类型选择:</span>
                </el-col>
                <el-col :span="5">
                  <el-select v-model="deTypevalue" placeholder="请选择文件类型">
                    <el-option v-for="item in options" :key="item.value" :label="item.name" :value="item.value">
                    </el-option>
                  </el-select>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
              <el-row>
                <el-col :span="3"><span> 上传文件:</span></el-col>
                <el-col :span="5">
                  <el-upload 
                    action="#" 
                    ref="deupload" 
                    :before-upload="beforedeupload"  
                    :on-preview="handlePreview"
                    :on-remove="handleRemove" 
                    multiple 
                    :file-list="mutiDeFileList" 
                    :auto-upload="false"
                    :http-request="mutiDefilesUpload">
                    <el-button slot="trigger" size="small" type="primary" icon="el-icon-folder-add">上传附件</el-button>
                  </el-upload>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
            </div>
          </div>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogdebugFile = false">取 消</el-button>
            <el-button type="primary" icon="el-icon-upload" @click="submitDeFiles">上传到服务器</el-button>
          </span>
        </el-dialog>
    
        <!-- 附件上传弹出框 -->
        <el-dialog title="上传文件" :visible.sync="dialogFile" width="50%">
          <div class="item list">
            <div>
              <el-row>
                <el-col :span="3"><span> 文件类型选择:</span>
                </el-col>
                <el-col :span="5">
                  <el-select v-model="fileTypevalue" placeholder="请选择文件类型">
                    <el-option v-for="item in options" :key="item.value" :label="item.name" :value="item.value">
                    </el-option>
                  </el-select>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
              <el-row>
                <el-col :span="3"><span> 上传文件:</span></el-col>
                <el-col :span="5">
                  <el-upload 
                    action="#" 
                    ref="upload"  
                    :before-upload="beforeupload" 
                    :on-preview="handlePreview" 
                    :on-remove="handleRemove" 
                    multiple
                    :file-list="mutiFileList" 
                    :auto-upload="false" 
                    :http-request="mutiFilesUpload">
                    <el-button slot="trigger" size="small" type="primary" icon="el-icon-folder-add">上传附件</el-button>
                  </el-upload>
                </el-col>
                <el-col :span="8" />
                <el-col :span="8" />
              </el-row>
            </div>
          </div>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogFile = false">取 消</el-button>
            <el-button type="primary" icon="el-icon-upload" @click="submitFiles">上传到服务器</el-button>
          </span>
        </el-dialog>
      </div>
    </template>
    <script>
      import axios from 'axios'
      import Pagination from '@/components/Pagination' // 引入分页组件
      import {uploadfile,workFilePage,workFileType,deleteFile} from '@/api/produce/taskInfo/index'
      export default {
        components: {Pagination}, //注册分页组件
        data() {
          return {
            pageSizes: [5, 10, 15, 20], //控制每页的数量
            DeFilesTableData: [], //调试附件表格
            filesTableData: [], //调试附件表格
            listLoading: true,
            dialogdebugFile: false, //调试附件上传弹出框控制 
            dialogFile: false, //附件上传弹出框控制 
            deTypevalue: '', //调试附件类型选择值
            fileTypevalue: '', //调试附件类型选择值
            detotal: 0, //调试附件表格数据总数
            filetotal: 0, //附件表格数据总数
            // 7a124e3e-24e3-b681-280e-01722ab1623e
            orderId: '11111',
            // 类型数组
            options: [],
            //单文件调试附件数据
            DebugfileList: [{
                name: '系统配置文件',
                businessType: 'CONFIGURATION',
                fileList: []
              },
              {
                name: 'newpreprocess',
                businessType: 'NEWPREPROCESS',
                fileList: []
              },
              {
                name:'newpreprocess-机型',
                businessType: 'MODEL',
                fileList: []
              },
              {
                name:'cfile',
                businessType: 'CFILE',
                fileList: []
              }
            ],
            //单文件附件数据
            fileList: [{
                name: '穿透力',
                businessType: 'PENETRATION',
                fileList: []
              },
              {
                name: '丝分辨力',
                businessType: 'SILKRESOLUTION',
                fileList: []
              },
              {
                name: '空间分辨力',
                businessType: 'SPATIALRESOLUTION',
                fileList: []
              },
              {
                name: '物质分辨',
                businessType: 'MATTERRESOLUTION',
                fileList: []
              },
              {
                name: '未出束曲线',
                businessType: 'UNBENDCURVE',
                fileList: []
              },
              {
                name: '出束曲线',
                businessType: 'EXITCURVE',
                fileList: []
              }
            ],
            mutiDeFileList: [], //多文件调试附件
            mutiFileList: [], //多文件附件
            DeFilesform: '', //调试附件文件流
            Filesform: '', //附件文件流
            // 分页1
            listDeFileQuery: {
              page: 1,
              limit: 5
            },
            // 分页2
            listFileQuery: {
              page: 1,
              limit: 5
            },
            flag:false,
            flag2:false,
          }
        },
        mounted() {
          this.getDeFilesTableData()
          this.getFilesTableData()
          this.getType()
        },
        methods: {
          //获取select下拉框内容
          getType() {
            workFileType().then(res => {
              this.options = res.data.rows
            })
          },
    
          // 获取调试附件表格数据
          getDeFilesTableData() {
            workFilePage(Object.assign(this.listDeFileQuery, {
              orderId: this.orderId,
              fileMaxType: 1
            })).then(res => {
              this.DeFilesTableData = res.data.rows
              this.detotal = res.data.total
            })
          },
    
          // 获取附件表格数据
          getFilesTableData() {
            workFilePage(Object.assign(this.listFileQuery, {
              orderId: this.orderId,
              fileMaxType: 2
            })).then(res => {
              this.filesTableData = res.data.rows
              this.filetotal = res.data.total
            })
          },
    
          // 单文件调试附件上传
          handelUploadDebugfile(e) {
            let file = e.file;
            let form = new FormData()
            let maxType = '1';
            let businessType = e.data.name;
            form.append('files', e.file);
            uploadfile(form, this.orderId, maxType, businessType).then(data => {
              this.getDeFilesTableData()
            })
          },
    
          // 单文件附件上传
          handelUploadfile(e) {
            let file = e.file;
            let form = new FormData()
            let maxType = '2';
            let businessType = e.data.name;
            form.append('files', e.file);
            uploadfile(form, this.orderId, maxType, businessType).then(data => {
              this.getFilesTableData()
            })
          },
    
          // 多文件调试附件上传1
          mutiDefilesUpload(e) {
            this.DeFilesform.append('files', e.file)
          },
          // 多文件调试附件上传到服务器
          submitDeFiles() {
            this.DeFilesform = new FormData()
              this.$refs.deupload.submit()
              let maxType = '1';
              let businessType = this.deTypevalue;
              let form = this.DeFilesform
            if (this.deTypevalue != '' && this.flag2) {
              uploadfile(form, this.orderId, maxType, businessType).then(data => {
                this.dialogdebugFile = false
                this.deTypevalue = ''
                this.$refs.deupload.clearFiles()
                this.flag2=false
                this.getDeFilesTableData()
              })
            } else {
              this.$notify({
                title: '警告',
                message: '请选择文件或者文件类型',
                type: 'warning'
              });
            }
          },
    
          //文件上传之前的钩子函数
          beforedeupload(file){
            if(file){
              this.flag2=true
            }
          },
          beforeupload(file){
            if(file){
              this.flag=true
            }
          },
    
          // 多文件附件上传到服务器
          mutiFilesUpload(e) {
            this.Filesform.append('files', e.file)
          },
          // 多文件附件上传到服务器
          submitFiles() {
              this.Filesform = new FormData()
              this.$refs.upload.submit()
              let maxType = '2';
              let businessType = this.fileTypevalue;
              let form = this.Filesform
            if (this.fileTypevalue != '' && this.flag) {
              uploadfile(form, this.orderId, maxType, businessType).then(data => {
                this.dialogFile = false
                this.fileTypevalue = ''
                this.$refs.upload.clearFiles()
                this.flag=false
                this.getFilesTableData()
              })
            } else {
              this.$notify({
                title: '警告',
                message: '请选择文件类型或文件',
                type: 'warning'
              });
            }
          },
    
          //  删除表格文件
          Delete(row) {
            this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning'
            }).then(() => {
              console.log(row.id)
              deleteFile({
                id: row.id
              }).then(() => {
                this.getDeFilesTableData()
                this.$notify({
                  title: '提示',
                  message: '删除成功',
                  type: 'success'
                })
              }).catch()
            })
          },
    
          //  下载表格文件
          download(row) {
            let id = row.id
            var elemIF = document.createElement('iframe');
            elemIF.src = '/api/produce/workFileInfo/downloadFile?id=' + id;
            elemIF.style.display = 'none';
            document.body.appendChild(elemIF);
          },
    
          //  移除
          handleRemove(file, fileList) {
            // console.log(file, fileList);
          },
          handlePreview(file) {
            // console.log(file);
          },
          // 单文件超出提示
          handleExceed(files, fileList) {
            this.$message.warning(`只能选择 1 个文件,请先删除当前文件`);
          },
          beforeRemove(file, fileList) {
            return this.$confirm(`确定移除 ${ file.name }?`);
          }
        }
      }
    
    </script>
    <style scoped>
      .el-upload-list__item{
        z-index: 9999;
        display: none;
      }
      .el-pagination{
        z-index: 99999;
        padding: 0 0 20px 5px;
      }
      .pagination-container[data-v-72233bcd]{
       z-index: 99999;
       padding: 0px 16px;
      }
      .el-col[data-v-431029e7]{
        border-radius: 4px;
        height: 40px;
        line-height: 40px;
        text-align: justify;
      }
      .list{
        padding-bottom: 15px;
      }
      .main {
        width: 80%;
        margin: 0 auto;
     }
      .item{
        margin-top: 20px;
        margin-bottom: 20px;
     }
      .el-button--small{
        margin-right: 160px;
      }
      .el-row{
        margin-bottom: 20px;
        &:last-child{
        margin-bottom:0;
       }
     }
      .el-col{
        border-radius: 4px;
        height: 40px;
        line-height: 40px;
        text-align: center;
      }
      .bg-purple-dark{
        background:#99a9bf;
     }
      .bg-purple{
        background:#d3dce6;
        }
      .bg-purple-ligh{
        background:#e5e9f2;
     }
      .grid-content{
        border-radius: 4px;
        min-height: 36px;
     }
      .row-bg{
        padding: 10px 0;
        background-color:#f9fafc;
     }
    </style>
    
    
    展开全文
  • ASP.NET上传文件用FileUpLoad就可以,但是对文件夹的操作却不能用FileUpLoad来实现。下面这个示例便是使用ASP.NET来实现上传文件夹并对文件夹进行压缩以及解压。ASP.NET页面设计:TextBox和Button按钮。TextBox中...

    ASP.NET上传文件用FileUpLoad就可以,但是对文件夹的操作却不能用FileUpLoad来实现。

    下面这个示例便是使用ASP.NET来实现上传文件夹并对文件夹进行压缩以及解压。

    ASP.NET页面设计:TextBox和Button按钮。

    TextBox中需要自己受到输入文件夹的路径(包含文件夹),通过Button实现选择文件夹的问题还没有解决,暂时只能手动输入。

    两种方法:生成rar和zip。

    1.生成rar

    using Microsoft.Win32;

    using System.Diagnostics;

    protected void Button1Click(object sender, EventArgs e)

    {

    RAR(@"E:\95413594531\GIS", "tmptest", @"E:\95413594531\");

    }

    ///

    ///压缩文件

    ///

    ///需要压缩的文件夹或者单个文件

    ///生成压缩文件的文件名

    ///生成压缩文件保存路径

    ///

    protected bool RAR(string DFilePath, string DRARName,string DRARPath)

    {

    String therar;

    RegistryKey theReg;

    Object theObj;

    String theInfo;

    ProcessStartInfo theStartInfo;

    Process theProcess;

    try

    {

    theReg = Registry.ClassesRoot.OpenSubKey(@"Applications\WinRAR.exe\Shell\Open\Command"); //注:未在注册表的根路径找到此路径

    theObj = theReg.GetValue("");

    therar = theObj.ToString();

    theReg.Close();

    therar = therar.Substring(1, therar.Length - 7);

    theInfo = " a" + " " + DRARName + "" + DFilePath +" -ep1"; //命令 + 压缩后文件名 + 被压缩的文件或者路径

    theStartInfo = new ProcessStartInfo();

    theStartInfo.FileName = therar;

    theStartInfo.Arguments = theInfo;

    theStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

    theStartInfo.WorkingDirectory = DRARPath ; //RaR文件的存放目录。

    theProcess = new Process();

    theProcess.StartInfo = theStartInfo;

    theProcess.Start();

    theProcess.WaitForExit();

    theProcess.Close();

    return true;

    }

    catch (Exception ex)

    {

    return false;

    }

    }

    ///

    ///解压缩到指定文件夹

    ///

    ///压缩文件存在的目录

    ///压缩文件名称

    ///解压到文件夹

    ///

    protected bool UnRAR(string RARFilePath,string RARFileName,string UnRARFilePath)

    {

    //解压缩

    String therar;

    RegistryKey theReg;

    Object theObj;

    String theInfo;

    ProcessStartInfo theStartInfo;

    Process theProcess;

    try

    {

    theReg = Registry.ClassesRoot.OpenSubKey(@"Applications\WinRar.exe\Shell\Open\Command");

    theObj = theReg.GetValue("");

    therar = theObj.ToString();

    theReg.Close();

    therar = therar.Substring(1, therar.Length - 7);

    theInfo = @" X " + " " + RARFilePath + RARFileName + " " + UnRARFilePath;

    theStartInfo = new ProcessStartInfo();

    theStartInfo.FileName = therar;

    theStartInfo.Arguments = theInfo;

    theStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

    theProcess = new Process();

    theProcess.StartInfo = theStartInfo;

    theProcess.Start();

    return true;

    }

    catch (Exception ex)

    {

    return false;

    }

    }

    注:这种方法在在电脑注册表中未找到应有的路径,未实现,仅供参考。

    2.生成zip

    通过调用类库ICSharpCode.SharpZipLib.dll

    增加两个类:Zip.cs和UnZip.cs

    (1)Zip.cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.IO;

    using System.Collections;

    using ICSharpCode.SharpZipLib.Checksums;

    using ICSharpCode.SharpZipLib.Zip;

    namespace UpLoad

    {

    ///

    ///功能:压缩文件

    /// creator chaodongwang 2009-11-11

    ///

    public class Zip

    {

    ///

    ///压缩单个文件

    ///

    /// 被压缩的文件名称(包含文件路径)

    /// 压缩后的文件名称(包含文件路径)

    /// 压缩率0(无压缩)-9(压缩率最高)

    /// 缓存大小

    public void ZipFile(string FileToZip, string ZipedFile, int CompressionLevel)

    {

    //如果文件没有找到,则报错

    if (!System.IO.File.Exists(FileToZip))

    {

    throw new System.IO.FileNotFoundException("文件:" + FileToZip + "没有找到!");

    }

    if (ZipedFile == string.Empty)

    {

    ZipedFile = Path.GetFileNameWithoutExtension(FileToZip) + ".zip";

    }

    if (Path.GetExtension(ZipedFile) != ".zip")

    {

    ZipedFile = ZipedFile + ".zip";

    }

    如果指定位置目录不存在,创建该目录

    //string zipedDir = ZipedFile.Substring(0,ZipedFile.LastIndexOf("\\"));

    //if (!Directory.Exists(zipedDir))

    //Directory.CreateDirectory(zipedDir);

    //被压缩文件名称

    string filename = FileToZip.Substring(FileToZip.LastIndexOf('\\') + 1);

    System.IO.FileStream StreamToZip = new System.IO.FileStream(FileToZip, System.IO.FileMode.Open, System.IO.FileAccess.Read);

    System.IO.FileStream ZipFile = System.IO.File.Create(ZipedFile);

    ZipOutputStream ZipStream = new ZipOutputStream(ZipFile);

    ZipEntry ZipEntry = new ZipEntry(filename);

    ZipStream.PutNextEntry(ZipEntry);

    ZipStream.SetLevel(CompressionLevel);

    byte[] buffer = new byte[2048];

    System.Int32 size = StreamToZip.Read(buffer, 0, buffer.Length);

    ZipStream.Write(buffer, 0, size);

    try

    {

    while (size < StreamToZip.Length)

    {

    int sizeRead = StreamToZip.Read(buffer, 0, buffer.Length);

    ZipStream.Write(buffer, 0, sizeRead);

    size += sizeRead;

    }

    }

    catch (System.Exception ex)

    {

    throw ex;

    }

    finally

    {

    ZipStream.Finish();

    ZipStream.Close();

    StreamToZip.Close();

    }

    }

    ///

    ///压缩文件夹的方法

    ///

    public void ZipDir(string DirToZip, string ZipedFile, int CompressionLevel)

    {

    //压缩文件为空时默认与压缩文件夹同一级目录

    if (ZipedFile == string.Empty)

    {

    ZipedFile = DirToZip.Substring(DirToZip.LastIndexOf("\\") + 1);

    ZipedFile = DirToZip.Substring(0, DirToZip.LastIndexOf("\\")) +"\\"+ ZipedFile+".zip";

    }

    if (Path.GetExtension(ZipedFile) != ".zip")

    {

    ZipedFile = ZipedFile + ".zip";

    }

    using (ZipOutputStream zipoutputstream = new ZipOutputStream(File.Create(ZipedFile)))

    {

    zipoutputstream.SetLevel(CompressionLevel);

    Crc32 crc = new Crc32();

    Hashtable fileList = getAllFies(DirToZip);

    foreach (DictionaryEntry item in fileList)

    {

    FileStream fs = File.OpenRead(item.Key.ToString());

    byte[] buffer = new byte[fs.Length];

    fs.Read(buffer, 0, buffer.Length);

    ZipEntry entry = new ZipEntry(item.Key.ToString().Substring(DirToZip.Length + 1));

    entry.DateTime = (DateTime)item.Value;

    entry.Size = fs.Length;

    fs.Close();

    crc.Reset();

    crc.Update(buffer);

    entry.Crc = crc.Value;

    zipoutputstream.PutNextEntry(entry);

    zipoutputstream.Write(buffer, 0, buffer.Length);

    }

    }

    }

    ///

    ///获取所有文件

    ///

    ///

    private Hashtable getAllFies(string dir)

    {

    Hashtable FilesList = new Hashtable();

    DirectoryInfo fileDire = new DirectoryInfo(dir);

    if (!fileDire.Exists)

    {

    throw new System.IO.FileNotFoundException("目录:" + fileDire.FullName + "没有找到!");

    }

    this.getAllDirFiles(fileDire, FilesList);

    this.getAllDirsFiles(fileDire.GetDirectories(), FilesList);

    return FilesList;

    }

    ///

    ///获取一个文件夹下的所有文件夹里的文件

    ///

    ///

    ///

    private void getAllDirsFiles(DirectoryInfo[] dirs, Hashtable filesList)

    {

    foreach (DirectoryInfo dir in dirs)

    {

    foreach (FileInfo file in dir.GetFiles("*.*"))

    {

    filesList.Add(file.FullName, file.LastWriteTime);

    }

    this.getAllDirsFiles(dir.GetDirectories(), filesList);

    }

    }

    ///

    ///获取一个文件夹下的文件

    ///

    /// 目录名称

    /// 文件列表HastTable

    private void getAllDirFiles(DirectoryInfo dir, Hashtable filesList)

    {

    foreach (FileInfo file in dir.GetFiles("*.*"))

    {

    filesList.Add(file.FullName, file.LastWriteTime);

    }

    }

    }

    }

    (2)UnZip.cs

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    ///

    ///解压文件

    ///

    using System;

    using System.Text;

    using System.Collections;

    using System.IO;

    using System.Diagnostics;

    using System.Runtime.Serialization.Formatters.Binary;

    using System.Data;

    using ICSharpCode.SharpZipLib.Zip;

    using ICSharpCode.SharpZipLib.Zip.Compression;

    using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

    namespace UpLoad

    {

    ///

    ///功能:解压文件

    /// creator chaodongwang 2009-11-11

    ///

    public class UnZipClass

    {

    ///

    ///功能:解压zip格式的文件。

    ///

    /// 压缩文件路径

    /// 解压文件存放路径,为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹

    /// 出错信息

    /// 解压是否成功

    public void UnZip(string zipFilePath, string unZipDir)

    {

    if (zipFilePath == string.Empty)

    {

    throw new Exception("压缩文件不能为空!");

    }

    if (!File.Exists(zipFilePath))

    {

    throw new System.IO.FileNotFoundException("压缩文件不存在!");

    }

    //解压文件夹为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹

    if (unZipDir == string.Empty)

    unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath));

    if (!unZipDir.EndsWith("\\"))

    unZipDir += "\\";

    if (!Directory.Exists(unZipDir))

    Directory.CreateDirectory(unZipDir);

    using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))

    {

    ZipEntry theEntry;

    while ((theEntry = s.GetNextEntry()) != null)

    {

    string directoryName = Path.GetDirectoryName(theEntry.Name);

    string fileName = Path.GetFileName(theEntry.Name);

    if (directoryName.Length > 0)

    {

    Directory.CreateDirectory(unZipDir + directoryName);

    }

    if (!directoryName.EndsWith("\\"))

    directoryName += "\\";

    if (fileName != String.Empty)

    {

    using (FileStream streamWriter = File.Create(unZipDir + theEntry.Name))

    {

    int size = 2048;

    byte[] data = new byte[2048];

    while (true)

    {

    size = s.Read(data, 0, data.Length);

    if (size > 0)

    {

    streamWriter.Write(data, 0, size);

    }

    else

    {

    break;

    }

    }

    }

    }

    }

    }

    }

    }

    }

    以上这两个类库可以直接在程序里新建类库,然后复制粘贴,直接调用即可。

    主程序代码如下所示:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Drawing;

    using Microsoft.Win32;

    using System.Diagnostics;

    namespace UpLoad

    {

    public partial class UpLoadForm : System.Web.UI.Page

    {

    protected void Page_Load(object sender, EventArgs e)

    {

    }

    protected void Button1_Click(object sender, EventArgs e)

    {

    if (TextBox1.Text == "") //如果输入为空,则弹出提示

    {

    this.Response.Write("");

    }

    else

    {

    //压缩文件夹

    string zipPath = TextBox1.Text.Trim(); //获取将要压缩的路径(包括文件夹)

    string zipedPath = @"c:\temp"; //压缩文件夹的路径(包括文件夹)

    Zip Zc = new Zip();

    Zc.ZipDir(zipPath, zipedPath, 6);

    this.Response.Write("");

    //解压文件夹

    UnZipClass unZip = new UnZipClass();

    unZip.UnZip(zipedPath+ ".zip", @"c:\temp"); //要解压文件夹的路径(包括文件名)和解压路径(temp文件夹下的文件就是输入路径文件夹下的文件)

    this.Response.Write("");

    }

    }

    }

    }

    本方法经过测试,均已实现。

    展开全文
  • 文件上传是我们作为开发者在日常工作中经常遇到的一个需求,各个流行的组件库中也都有现成的组件可以很方便的直接调用。具体的用法不再赘述,小伙伴们可以在组件库中查看demo,这里笔者主要介绍下如何实现一个Upload...

    64640e7ab915ac827742edf4ceaab8fc.png

    文件上传是我们作为开发者在日常工作中经常遇到的一个需求,各个流行的组件库中也都有现成的组件可以很方便的直接调用。具体的用法不再赘述,小伙伴们可以在组件库中查看demo,这里笔者主要介绍下如何实现一个Upload组件。

    组件支持的功能如下:

    • 上传进度条显示
    • 图片预览
    • 自定义上传请求方法
    • 图片数量限制
    • 支持拖拽上传
    • 使用koa以及对应的中间件实现图片上传服务器接口

    最终效果图如下:

    3f28a501961b4033b266b08cef9ed6cb.png
    相关资料:
    • 组件源代码
    • 服务端上传接口源代码
    • 在线demo

    搭建文件上传服务器

    在书写前端Upload组件之前,首先需要通过Node.js来搭建一个服务器。使用到的一些库如下:

    • Koa: Node.js服务端框架
    • koa-static: Koa静态服务器中间件
    • @koa/multer: Koa文件上传中间件
    • @koa/router: Koa路由中间件
    • @koa/cors: 解决跨域问题

    服务端的代码比较简单,源码如下:

    const path = require('path');
    const Koa = require('koa');
    const Router = require('@koa/router');
    const multer = require('@koa/multer');
    const cors = require('@koa/cors');
    const serve = require('koa-static');
    const app = new Koa();
    
    
    // deploy to heroku will use environment variable
    const PORT = process.env.PORT || 3000;
    const router = new Router();
    // set upload files store directory
    const upload = multer({ dest: 'uploads' });
    app.use(serve('.'));
    app.use(cors());
    app.use(router.routes());
    app.use(router.allowedMethods());
    
    router.post('/upload', upload.single('file'), async (ctx) => {
      const domain = ctx.protocol + '://' + ctx.host + '/';
      const { path, originalname } = ctx.file;
      const data = { path: domain + path, filename: originalname };
      ctx.body = {
        code: 200,
        data,
        message: '成功'
      };
    })
    app.listen(PORT, () => {
      console.log(`server is listening on port ${PORT}`);
    });
    

    我们将项目根目录作为静态服务器的根目录,之后我们就可以直接通过路径来访问项目中的资源。如:http://localhost:3000/uploads/xxxx (在本地启动服务) 可以直接访问uploads下我们上传的图片。

    上边代码的主要逻辑是帮我们实现了上传接口,并在上传完成后将图片的访问路径进行拼接,然后作为响应返回。前端可以在接收到响应后通过路径进行图片预览。

    最终我们是将服务器部署到了heroku上,具体的部署过程参考这里:传送门

    组件设计

    组件支持的API如下(参考element ui):

    • name : 文件上传时前端需要和服务端约定的key
    • limit: 文件上传数量
    • fileList: 已经上传的文件列表
    • action: 文件上传地址
    • beforeUpload: 上传之前的钩子函数
    • onChange: 上传过程中文件信息发生更改触发的回调
    • onSuccess/onError/onProgress: 上传成功/错误/进度回调函数
    • onExceed: 超出最大上传数量时触发的回调
    • data: 额外参数组成的对象,最终会遍历以key/value键值对的形式appendformData
    • multiple: 是否支持多个文件上传
    • accept: 上传接收的文件类型
    • customHttpRequest: 支持自定义请求函数
    • drag: 是否启用拖拽上传

    在编码之前,我们先看下组件的基础用法:

    <template>
      <go-upload name="file" :limit="3" multiple on-exceed="onExceed" :action="action">
        <go-button color="primary">click to upload</go-button>
      </go-upload>
    </template>
    
    <script>
    export default {
      data () {
        return {
          action: 'https://afternoon-dawn-09444.herokuapp.com/upload'
        };
      },
      methods: {
        onExceed() {
    
        }
      }
    };
    </script>
    

    组件通过插槽的形式来放置文件上传的触发按钮,接收nameaction属性,并且通过multiple属性支持多文件上传

    下面我们开始组件的实现。

    触发Inputchange事件

    根据组件的使用方式,我们可以写出下面的代码:

    <template>
      <div class="go-upload">
        <input
          class="go-upload-input"
          ref="input"
          type="file"
        >
        <div class="go-upload-trigger" >
          <slot></slot>
        </div>
      </div>
    </template>
    <script>
    export default {
      props: {
        name: { type: String, default: 'file' },
        action: {
          type: String,
          required: true
        },
      }
    }
    </script>
    

    只要点击type=file对应的input,就会弹出对应的上传文件窗口。但是由于原生的input比较丑,我们可以将其隐藏(display:none),然后通过手动触发inputclick事件来进而触发inputchange事件。

    具体的细节在mdn 中有介绍:

    02181a990095407dae94e875d7b13de3.png

    在组件中,当用户点击slot中的按钮时,click事件会冒泡到go-upload-trigger对应的div,我们可以监听go-upload-triggerclick事件,然后再调用inputclick进而弹出上传窗口:

    <template>
      <div class="go-upload">
        <input
          class="go-upload-input"
          ref="input"
          type="file"
        >
        <div class="go-upload-trigger" @click="onClickTrigger">
          <slot></slot>
        </div>
      </div>
    </template>
    <script>
    export default {
      // ...
      methods: {
        onClickTrigger () {
          this.$refs.input.click();
        }
      }
    }
    </script>
    

    通过这种方式,我们便可以实现一个比较美观的按钮来进行点击上传文件。

    在上传之前,我们先整理一下要做的事情:

    • 实现上传方法封装
    • 获取到用户选择的文件(e.target.files)
    • 整理XMLHttpRequest上传所需参数,并调用上传方法
    • 在上传过程中更新fileList的状态,方便进行展示

    实现XMLHttpRequest文件上传方法

    XMLHttpRequest的详细用法可以看这里: XMLHttpRequest

    文件上传可以使用FormData来实现,FormData可以轻易地构造出一组代表form字段和它们值的key/value键值对,而不用我们再在页面中书写form表单。

    为了方便使用,用户传入的data是一个对象,我们需要遍历其中的每一项,然后将key/value通过append方法追加到formData中,传给服务端。源码如下:

    // XMLHttpRequest常用的三个事件: error/load/progress
    import { entries } from '@/shared/util';
    
    const processResponse = (response) => {
      if (typeof response === 'string') {
        try {
          return JSON.parse(response);
        } catch (e) {
          return response;
        }
      }
      return response;
    };
    const request = ({
      url,
      name,
      file,
      data,
      onSuccess,
      onError,
      onProgress
    }) => {
      const xhr = new XMLHttpRequest();
      const formData = new FormData();
      // 传入文件key,value对
      formData.append(name, file);
      // 遍历对象方便为formData添加key,value对
      entries(data, (key, val) => formData.append(key, val));
      // 监听上传的progress事件来监听上传过程,显示上传进度
      xhr.upload.addEventListener('progress', (e) => {
        e.percent = e.loaded / e.total * 100;
        onProgress(e);
      });
      xhr.open('POST', url);
      xhr.send(formData);
      xhr.addEventListener('load', () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          const response = processResponse(xhr.response);
          onSuccess(response);
        } else {
          onError(new Error('upload request failed!'));
        }
      });
    
      xhr.addEventListener('error', (e) => {
        onError(e);
      });
      return xhr;
    };
    
    export default request;
    

    对应的参数含义如下:

    • url 上传地址
    • name 上传文件的key值,需要和后端约定
    • file 上传的 File 对象
    • data 除文件外的其它参数,类型为 object
    • onSuccess 上传成功后的回调
    • onError 上传失败后的回调
    • onProgress 上传进度回调

    最终request函数会返回xhr,方便之后调用xhr的属性和方法,如:通过xhr.abort()来取消请求。

    注意:xhr.uploadprogress事件必须在调用xhr.open之前进行监听,否则不会生效(xhr.upload.onprogress doesn't work)

    开始上传

    用户选择的文件在inputchange事件的事件对象中:e.target.files,然后通过uploadFiles进行上传文件

    <script>
    export default {
      methods: {
        onInputChange (e) {
          // e.target.files is pseudo array, need to convert to real array
          const rawFiles = Array.from(e.target.files);
          this.uploadFiles(rawFiles);
        },
        uploadFiles (rawFiles) {
          const filesLen = rawFiles.length + this.files.length;
          if (this.limit && this.limit < filesLen) {
            return this.onExceed(rawFiles, this.files);
          }
          this.startUpload(rawFiles);
        }
      }
    }
    </script>
    

    上传之前会通过limit来判断上传的数量是否超过了限制,如果超过的话会调用用户传入的onExceed方法,并停止上传。

    注意:e.target.files获取到的是一个伪数组,需要我们转换成真正的数组才能调用数组的方法。

    startUpload方法中,我们会遍历用户选择的每个文件,然后依次进行上传。在真正上传之前,会执行normalizeFiles将原生的file对象进行格式化,处理成组件中方便使用的格式:

    <script>
    export default {
      methods: {
        startUpload (rawFiles) {
          rawFiles.forEach(rawFile => {
            const file = this.normalizeFiles(rawFile);
            if (!this.beforeUpload || this.beforeUpload()) {
              this.upload(file);
            }
          });
        },
        normalizeFiles (rawFile) {
          const file = {
            name: rawFile.name, // 文件名
            size: rawFile.size, // 文件尺寸
            type: rawFile.type, // 文件类型
            percent: 0, // 上传进度
            uid: Date.now() + this.tempIndex++, // 唯一标识
            status: 'init', // value list: init pending success failure
            raw: rawFile // 原生文件对象
          };
          // concat does not change the existing arrays, but instead returns a new array
          this.files.push(file);
          return file;
        },
      }
    }
    </script>
    

    在格式化file对象的时候,需要我们生成唯一的uid来标识每一个上传的文件信息。这里我们使用了Date.now()来生成唯一值,但是在进行多文件上传的时候,会同时上传多个文件,导致uid重复。所以我们为其加上一个自增的tempIndex,防止重复。

    在拿到格式化后的文件后,将会进入真正的上传环节:

    <script>
    export default {
      methods: {
        upload (file) {
          const options = {
            url: this.action,
            name: this.name,
            file: file.raw,
            data: this.data,
            onSuccess: this.handleSuccess.bind(this, file),
            onError: this.handleError.bind(this, file),
            onProgress: this.handleProgress.bind(this, file)
          };
          file.status = 'pending';
          this.onChange(file, this.files);
          const req = this.customHttpRequest(options);
          if (req instanceof Promise) {
            req.then(options.onSuccess, options.onError);
          }
        },
        handleSuccess (file, response) {
          file.status = 'success';
          this.$set(file, 'response', response);
          // Not only front end can implement picture preview but also back end can do it. Here make use of back end api
          this.$set(file, 'url', response.data.path);
          this.onChange(file, this.files);
          this.onSuccess(response, file, this.files);
        },
        handleError (file, error) {
          file.status = 'failure';
          this.onError(error, file, this.files);
        },
        handleProgress (file, event) {
          file.percent = event.percent;
          this.onChange(file, this.files);
          this.onProgress(event, file, this.files);
        },
      }
    }
    </script>
    

    upload为真正发起请求的函数,其内部首先收集了请求发起所需要的所有参数,之后将文件状态改为pending后进行上传操作。其中对应的回调函数所实现的功能如下:

    • handleSuccess: 修改文件状态为success;添加response属性为请求响应;添加url属性为文件预览地址
    • handleProgress: 设置文件的上传进度百分比
    • handleError: 修改文件状态为failure

    现在我们可以成功的处理上传过程中文件的不同状态,接下来我们在页面中进行展示。

    上传列表

    所有的正在上传和已经上传完成的文件会放到files中来进行展示:

    <script>
    export default {
      data () {
        return {
          files: [],
        };
      },
    }
    </script>
    

    封装upload-list组件,并传入files展示文件的整个上传过程:

    <template>
      <div class="go-upload-list">
        <div :class="['go-upload-list-item',file.status]" v-for="(file,i) in files" :key="file.uid">
          <!--  FIXME:code in here is so chaos, can it become more elegance?  -->
          <div class="go-upload-list-item-img">
            <go-icon v-if="file.status === 'pending'" class="go-upload-item-img-loading" name="loading"></go-icon>
            <template v-else-if="file.status === 'success'">
              <img v-if="isImage(file.type)" class="go-upload-list-item-img" :src="file.url" alt="">
              <go-icon v-else class="go-upload-item-file" name="file"></go-icon>
            </template>
            <go-icon v-else class="go-upload-item-img-error" name="picture"></go-icon>
          </div>
          <div class="go-upload-list-item-name">
            <span>{{ file.name }}</span>
            <my-progress v-if="file.status === 'pending'" :percent="file.percent"></my-progress>
          </div>
        </div>
      </div>
    </template>

    这里会利用到之前格式化后的文件信息,用于展示文件的状态、加载进度条等,并展示图片上传成功后的缩略图。

    拖拽上传

    我们也支持用户将文件拖拽到一个拖拽区域内进行上传。通过drop事件的事件对象中的e.dataTransfer.files来获取到上传的文件对象,然后和普通上传一样对文件对象处理并发送XMLHttpRequest请求。代码如下:

    <template>
      <div
        class="go-upload-dragger"
        :class="{dragging}"
        @dragenter="onDragenter"
        @dragleave="onDragleave"
        @dragover="onDragover"
        @drop="onDrop"
        @click="onClick"
      >
        <go-icon class="go-upload-dragger-icon" name="upload"></go-icon>
        <div class="go-upload-dragger-describe">
          <span>Drop file here or click to upload</span>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'UploadDragger',
      data () {
        return {
          dragging: false
        };
      },
      methods: {
        onDragenter (e) {
          this.dragging = true;
          e.stopPropagation();
          e.preventDefault();
        },
        onDragleave (e) {
          this.dragging = false;
          e.stopPropagation();
          e.preventDefault();
        },
        onDragover (e) {
          e.stopPropagation();
          e.preventDefault();
        },
        onDrop (e) {
          this.dragging = false;
          e.stopPropagation();
          e.preventDefault();
          const files = e.dataTransfer.files;
          this.$emit('handle-files', files);
        },
        onClick () {
          this.$emit('on-click');
        }
      }
    };
    </script>
    

    在进入拖拽区域后,我们会设置一个布尔值dragging来动态控制class,实现用户将文件拖入拖拽区域之后的交互效果。当用户在拖拽区域内松开文件时,调用drop事件,此时会将文件对象files通过this.$emit('handle-files',files)发送给upload组件来处理。

    <template>
      <div class="go-upload">
        <!--  omit other code ...  -->
        <upload-dragger v-if="drag" @on-click="onClickTrigger" @handle-files="uploadFiles"></upload-dragger>
        <div
          v-else
          class="go-upload-trigger"
          @click="onClickTrigger"
        >
          <slot></slot>
        </div>
      </div>
    </template>
    <script>
    export default{
      methods: {
        onClickTrigger () {
          this.$refs.input.click();
        },
        uploadFiles (rawFiles) {
          const filesLen = rawFiles.length + this.files.length;
          if (this.limit && this.limit < filesLen) {
            return this.onExceed(rawFiles, this.files);
          }
          this.startUpload(rawFiles);
        },
      }
    }
    </script>
    

    父组件中会通过@来监听handle-files对应的方法,并调用之前的上传函数,此后的上传过程与普通上传完全相同。上边代码中,拖拽区域也可以起到上传操作触发按钮的作用,点击区域后,会调用onClickTrigger方法来唤起文件选择界面。

    mdn 中有对拖拽上传进行介绍,有兴趣的小伙伴可以进行查阅:

    f54cf8f01e39c6a4f9b27d850cc61dde.png

    到这里,我们已经实现了上传组件的一些常见功能,可以进行一些开心的尝试了 !

    结语

    组件完成后,可以部署到GitHub Pages在网络中进行分享,具体的部署过程:部署 Vue 项目到 GitHub Pages

    希望在看完这篇文章后能帮助阅读的小伙伴明白上传组件的具体实现逻辑,并且可以更好的使用社区流行框架中的Upload组件,并对其进行二次封装。

    参考资料:

    • Using files from web applications
    • Element
    • heroku
    展开全文
  • 使用单文件Vue 组件化开发模式 基于 npm + webpack + babel 开发,支持 ES2015 高质量、功能丰富 友好的 API ,自由灵活地使用空间 详细、友好的文档,事无巨细 最近做一个后台系统用的功能 总结下遇见的...
  • ElementUI的Upload组件携带表单数据进行手动上传 项目需求本来是文件单独上传,再提交表单数据,请求两次接口。现在需求有变,要求在触发表单传输事件的同时上传文件,也就是提交表单数据和上传文件同步进行,请求一...
  • vue文件上传组件 upload ,拥有支持多种格式文件上传,单文件文件等都支持,许多项目现在都少不了文件上传功能,但是vue 的upload组件如果直接引用,肯定也有一些不方便之处,有的时候需要传参数,需要手动触发...
  • vue文件上传组件 upload ,拥有支持多种格式文件上传,单文件文件等都支持,许多项目现在都少不了文件上传功能,但是vue 的upload组件如果直接引用,肯定也有一些不方便之处,有的时候需要传参数,需要手动触发...
  • 可以设置文件选择后自动上传或者手动触发上传,并且手动触发可以自定义上传逻辑。可以限制文件格式和大小,比如:jpeg等之类的。设置缩略图模板。控制文件列表二、代码及注意事项ref="upload"action="" // 注意点一:...
  • this.fileList = this.fileList.slice(-1); 例子:` beforeUpload(file, fileList) { console.log(fileList);...//限制文件只能上传一个 this.fileList = this.fileList.slice(-1); const isZip = f
  • 背景 平时工作中经常会遇到需要上传文件的情况,如果你...ant design 手动上传文件 antd官网有手动上传的demo:  在这里简单写一写实现,主要有 在jsx中引入Upload组件,将 fileList 作为props传入,fileList为...
  • Vue使用Elenent的上传组件.实现单文件上传. <template> <div> <el-upload action="" :auto-upload='false' :file-list="fileList" :...
  • // 遇到的问题就是:在把上传文件的数组提交给后台时,后台一直提示上传的文件为空,收不到前台的上传文件,原因可能是: // 第一种原因:看handleUpload()方法是否绑定到dom了,上传文件前的方法一定要写上,要...
  • 使用element-ui的上传组件时,你使用的是自动上传(即选择完文件就立马上传...这需要把自动上传改为手动上传。 主要有两个步骤,首先是选取文件,第二部是点击上传(这一步做参数拼接)。上代码: html部分 <...
  • vue axios 实现上传文件

    2018-10-19 16:46:36
    1 新建一个用来上传文件的axios,不同普通请求后台的axios,因为上传文件不能手动设置请求头  var uploadAxios = axios.create({}),  Vue.prototype.$uploadAxios = uploadAxios;   注意: 不要设置请求头...
  • Spring Boot+Vue+FastDFS 实现前后端分离文件上传但是,之前和小伙伴们提到的方案,是基于 session 来做认证的,所以并不需要考虑携带令牌的问题,但是在前后端分离开发中,我们可能采用 JWT 或者是 OAuth2+JWT 的...
  • 文章目录1....Spring Boot+Vue+FastDFS 实现前后端分离文件上传 但是,之前和小伙伴们提到的方案,是基于 session 来做认证的,所以并不需要考虑携带令牌的问题,但是在前后端分离开发中,我们可能采
  • vue+element upload 手动上传

    千次阅读 2020-06-19 10:50:35
    限制文件类型,以及文件大小。 <template> <el-upload style="padding:20px" class="upload-demo" ref="upload" :before-upload="beforeUpload" :action="url" :on-preview="handlePreview" :on-...
  • 文件上传重点在于将file文件传给后端,而before-upload的参数就是可以获得file,http-request也可以,不过他的file文件还要从参数里面找,http-request之所以要用是因为 upload自带的actions属性我不需要,所以需要...
  • 这是一个图片上传的功能需求,当用户...可以帮助用户简单、快捷的实现文件上传功能,同时还提供了丰富的属性来实现对文件的各种操作。HTML构建这里我们利用ElementUI提供的组件el-upload来实现图片上传的功能,Elem...
  • vue+elementUI的文件上传文件下载

    千次阅读 2020-01-16 15:52:49
    大致的功能需求就是这样了,上传文件的组件用的是element-UI自带的组件 配置参数: 我使用的是手动上传模块 参数 说明 action 必选参数,上传的地址 multiple 是否支持多选文件 limit 最大允许上传个数 ...
  • 1,让原来的Input 框隐藏起来 2, 当我们点击按钮的时候,手动触发原来Input 的点击...fileUpload.vue <template> <div> <!-- <p class="text-center">hello world</p> --> <i.

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 203
精华内容 81
关键字:

vue手动上传文件

vue 订阅