首页 > 编程 > JavaScript > 正文

vue webuploader 文件上传组件开发

2019-11-19 15:19:22
字体:
来源:转载
供稿:网友

最近项目中需要用到百度的webuploader大文件的分片上传,对接后端的fastdfs,于是着手写了这个文件上传的小插件,步骤很简单,但是其中猜到的坑也不少,详细如下:

一、封装组件

引入百度提供的webuploader.js、Uploader.swf

css样式就直接写在组件里面了 

<template> <div>  <div id="list" class="uploader-list"></div>  <div id="wrapper">   <div class="uploader-container">    <div :id="id" limitSize="1" :ext="ext"></div>    <el-button style="margin-bottom:10px;float:left;" size="small" :loading="uploadLoading" type="success" @click="start">上传到服务器</el-button>    <el-button style="margin-left: 20px;margin-bottom:10px;float:left;" :disabled="stopBtn" size="small" type="danger" @click="stop">暂停上传</el-button>   </div>  </div>  <div class="el-upload__tip">{{tip}}</div>  <div class="file-list">   <ul class="el-upload-list el-upload-list--text">    <li v-for="file in fileList" :class="['el-upload-list__item', 'is-' + file.status]" :key="file">     <a class="el-upload-list__item-name">      <i class="el-icon-document"></i>{{file.name}}     </a>     <label class="el-upload-list__item-status-label">      <i :class="{'el-icon-upload-success': true,'el-icon-circle-check': listType === 'text',     'el-icon-check': ['picture-card', 'picture'].indexOf(listType) > -1}"></i>     </label>     <i class="el-icon-close" @click="removeFile(file)"></i>     <el-progress      v-if="file.status === 'uploading'"      :type="listType === 'picture-card' ? 'circle' : 'line'"      :stroke-width="listType === 'picture-card' ? 6 : 2"      :percentage="file.percentage">     </el-progress>    </li>   </ul>  </div> </div></template><script> import '../js/jquery.js' import '../js/webuploader.js' import { Base64 } from 'js-base64' import CryptoJS from 'crypto-js'; export default{  name: 'fileUpload',  props: {   id: {    type: String,    default: function(){     return "filePicker";    }   },   //上传提示   tip: {    type: String,    default: function(){     return "";    }   },   //文件后缀名限制   ext: {    type: String,    default: function(){     return "jpg,jpeg,png,pdf,mp4,avi.mp3";    }   },   //分片大小设置   chunkSize: {    type: Number,    default: function(){     return 2097152;    }   },   //分片上传重试次数   chunkRetry: {    type: Number,    default: function(){     return 1;    }   },   //是否自动上传   auto: {    type: Boolean,    default: function(){     return false;    }   },   //上传文件大小限制   sizeLimit: {    type: Number,    default: function(){     return 209715200;    }   },   //上传文件数量限制   countLimit: {    type: Number,    default: function(){     return 5;    }   }  },  data(){   return{    appId: AppConfig.appId,    securityKey: AppConfig.securityKey,    checkUrl: AppConfig.checkUrl,    uploadUrl: AppConfig.uploadUrl,    mergeUrl: AppConfig.mergeUrl,    previewName: '选择文件',    wul_fileMd5: '',    wul_size: 0,    wul_fileName: '',    wul_chunk: 0,    wul_uploader: '',    fileList: [],    listType: 'text',    percentage: 0,    fileObject: {     uid: '',     name: '',     ext: '',     type: '',     status: '',     percentage: 0,     url: ''    },    uploadLoading: false,    stopBtn: true   }  },  methods: {   /**    * 获取当前上传列表中的文件    * @returns {Array|*}    */   getFileList: function(){    return this.fileList;   },   //绑定事件   wul_init: function() {    //提示只能选择一个文件    this.wul_uploader.on('filesQueued', function (files) {     if (files.length > 1) {      this.$message({       message: '请选择一张图片',       type: 'error'      });      for (var i = 0; i < files.length; i++) {       this.wul_uploader.cancelFile(files[i]);      }      this.wul_uploader.reset();      this.wul_fileMd5 = "";      this.wul_size = 0;      this.wul_fileName = "";      this.wul_chunk = 0;  //当前切片数     }else{      if( this.fileList.length == this.countLimit ){       this.$message({        message: '已经达到上传文件限制数量',        type: 'error'       });      }else{       //此时往需要上传的文件列表中添加文件       let file = {        uid: Date.now() + this.tempIndex++,        name: files[0].name,        type: files[0].type,        ext: files[0].ext,        status: "ready",        percentage: 0       }       this.fileObject = file;       this.fileList.push(this.fileObject);      }     }    }.bind(this));    //文件校验格式和大小    this.wul_uploader.on('error', function (type) {      debugger     if (type == 'Q_EXCEED_SIZE_LIMIT') {      this.$message({       message: '文件超过指定大小',       type: 'error'      });     }     if (type == 'Q_TYPE_DENIED') {      this.$message({       message: '文件格式错误,请选择文件',       type: 'error'      });     }     if (type == 'F_EXCEED_SIZE') {      this.$message({       message: "文件超过" + this.sizeLimit / 1024 / 1024 + "M",       type: 'error'      });     }    }.bind(this));    //上传进度    this.wul_uploader.on('uploadProgress', function (file, percentage) {     this.percentage = percentage * 100;     this.fileObject.status = "uploading";     this.fileObject.percentage = this.percentage;     console.log(this.fileObject.percentage);    }.bind(this));    //每次切片上传完成之后的判断    this.wul_uploader.on('uploadAccept', function (object, ret) {     if (ret.responseCode != 0) {      this.wul_uploader.cancelFile(this.wul_uploader.getFiles()[0].id);     }    });    this.wul_uploader.on('uploadBeforeSend', function(object, data, headers) {     console.log(data);    });   },   option: function(key, val) {    this.wul_uploader.option(key, val);    var options = this.wul_uploader.options;    this.wul_uploader.destroy();  //注销uploader    this.wul_uploader = WebUploader.create(options);    this.wul_init();   },   start: function(){    if(this.wul_uploader.getFiles()[0] != null) {     this.wul_uploader.upload(this.wul_uploader.getFiles()[0].id);     this.uploadLoading = true;     this.stopBtn = false;    } else {     this.$message({      message: "请选择上传文件",      type: 'error'     });    }   },   stop: function(){    this.wul_uploader.cancelFile(this.wul_uploader.getFiles()[0].id);   },   removeFile: function(file){    this.fileList.splice(this.fileList.indexOf(file), 1);   },   change: function(){    this.option('accept', {     title: 'Images',     extensions: 'gif,jpg,jpeg,bmp,png'    });   }  },  mounted(){   WebUploader.Uploader.register({    "before-send-file": "beforeSendFile",    "before-send": "beforeSend",    "after-send-file": "afterSendFile",   }, {    beforeSendFile: function (file) {     var deferred = WebUploader.Deferred();     this.wul_uploader.md5File(file).then(function (val) {      this.wul_fileMd5 = val;      this.wul_size = file.size;      this.wul_fileName = file.name;      var timestamp = Date.parse(new Date()) / 1000;      var signParam = "{chunkSize=" + this.chunkSize + ", fileMd5=" + this.wul_fileMd5 + ", size=" + this.wul_size + ", timestamp=" + timestamp + "}";      var sign = Base64.encode(CryptoJS.HmacSHA1(signParam, this.securityKey));      // 获取断点续传位置      jQuery.ajax({       type: "POST",       // 测试       url: this.checkUrl,       data: {        // 文件大小        size: this.wul_size,        // 文件唯一标记        fileMd5: this.wul_fileMd5,        // 切片大小        chunkSize: this.chunkSize,        // 签名        sign: sign,        // 应用分配id        appId: this.appId,        // 当前时间戳        timestamp: timestamp       },       dataType: "json",       // 上传失败       error: function (XMLHttpRequest, textStatus, errorThrown) {        this.$message({         message: "上传失败...",         type: 'error'        });        this.uploadLoading = false;        this.stopBtn = true;       }.bind(this),       success: function (response) {        if (response.responseCode == 0) { // 切片获取成功         this.wul_chunk = response.chunk;         deferred.resolve();        } else { // 切片获取失败,请求成功         this.wul_uploader.cancelFile(file);  //取消文件上传         this.$message({          message: "切片检查失败,请联系管理员",          type: 'error'         });         deferred.resolve();         this.uploadLoading = false;         this.stopBtn = true;        }       }.bind(this)      });      return deferred.promise();     }.bind(this));     return deferred.promise();    }.bind(this),    beforeSend: function (block) {     var deferred = WebUploader.Deferred();     if (block.chunk < this.wul_chunk) {      return deferred.reject();     }     this.wul_uploader.md5File(block.blob).then(function (chunkMd5) {      var timestamp = Date.parse(new Date()) / 1000;      var signParam = '{chunk=' + block.chunk + ', chunkMd5=' + chunkMd5 + ', chunkSize=' + this.chunkSize + ', fileMd5=' + this.wul_fileMd5 + ', size=' + this.wul_size + ', timestamp=' + timestamp + '}';      var signTemp = CryptoJS.HmacSHA1(signParam, this.securityKey);      var sign = Base64.encode(signTemp);  //获取sign值      this.wul_uploader.options.formData = {       'timestamp': timestamp,       'appId': this.appId,       'chunk': block.chunk,       'chunkSize': this.chunkSize,       'fileMd5': this.wul_fileMd5,       'chunkMd5': chunkMd5,       'size': this.wul_size,       'sign': sign      };      deferred.resolve();     }.bind(this))     return deferred.promise();    }.bind(this),    afterSendFile: function (file) {     var timestamp = Date.parse(new Date()) / 1000;     var signParam = "{chunkSize=" + this.chunkSize + ", fileMd5=" + this.wul_fileMd5 + ", fileName=" + file.name + ", size=" + this.wul_size + ", timestamp=" + timestamp + "}";     var sign = Base64.encode(CryptoJS.HmacSHA1(signParam, this.securityKey));     // 如果分块上传成功,则通知后台合并分块     jQuery.ajax({      type: "POST",      url: this.mergeUrl,      data: {       appId: this.appId,       fileMd5: this.wul_fileMd5,       fileName: file.name,       chunkSize: this.chunkSize,       sign: sign,       size: this.wul_size,       timestamp: timestamp      },      success: function (response) {       if (response.responseCode == 0) {        this.fileObject.status = "success";        this.fileObject.percentage = 100;        this.fileObject.url = response.filePath;       } else {        this.fileObject.status = "exception";        this.$message({         message: "上传失败,失败原因:" + response.responseMsg,         type: 'error'        });       }       this.uploadLoading = false;       this.stopBtn = true;       this.wul_uploader.reset();       this.wul_fileMd5 = "";       this.wul_size = 0;       this.wul_fileName = "";       this.wul_chunk = 0;  //当前切片数      }.bind(this)     });    }.bind(this)   });   this.wul_uploader = WebUploader.create({    // swf文件路径    swf: '../js/Uploader.swf',    // 文件接收服务端。    server: this.uploadUrl,    // 定义选择按钮    pick: {     "id": "#" + this.id,     "innerHTML": this.previewName    },    // 自动上传    auto: this.auto,    // 禁止浏览器打开文件    disableGlobalDnd: true,    // 添加截图功能    paste: '#wrapper',    // 定义拖动面板    dnd: '#wrapper',    // 分片上传    chunked: true,    // 分片大小为2M    chunkSize: this.chunkSize,    // 分片上传失败重试次数    chunkRetry: this.chunkRetry,    // 图片不做压缩    compress: false,    // 队列设置10个,为了选择多个文件的时候能提示    fileNumLimit: 10,    // 提前准备好下一个文件    prepareNextFile: true,    // 限制单个文件大小    fileSingleSizeLimit: this.sizeLimit,    //线程数    threads : 1,    // 限制格式    accept: {     title: "access",     extensions: this.ext    }   });   this.wul_init();  } }</script><style> /* ----------------Reset Css--------------------- */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video, input {  margin: 0;  padding: 0;  border: none;  outline: 0;  font-size: 100%;  font: inherit;  vertical-align: baseline; } html, body, form, fieldset, p, div, h1, h2, h3, h4, h5, h6 {  -webkit-text-size-adjust: none; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {  display: block; } body {  font-family: arial, sans-serif; } ol, ul {  list-style: none; } blockquote, q {  quotes: none; } blockquote:before, blockquote:after, q:before, q:after {  content: '';  content: none; } ins {  text-decoration: none; } del {  text-decoration: line-through; } table {  border-collapse: collapse;  border-spacing: 0; } /* ------------ */ #wrapper {  width: 100%;  margin: 0 auto;  height: 35px; } .img-preview {  width: 160px;  height: 90px;  margin-top: 1em;  border: 1px solid #ccc; } .cropper-wraper {  position: relative; } .upload-btn {  background: #ffffff;  border: 1px solid #cfcfcf;  color: #565656;  padding: 10px 18px;  display: inline-block;  border-radius: 3px;  margin-left: 10px;  cursor: pointer;  font-size: 14px;  position: absolute;  right: 1em;  bottom: 2em; } .upload-btn:hover {  background: #f0f0f0; } .uploader-container{  width: 100%;  font-size: 10px; } .webuploader-container {  position: relative;  width: 100px;  height: 21px;  float: left; } .webuploader-element-invisible {  position: absolute !important;  clip: rect(1px 1px 1px 1px); /* IE6, IE7 */  clip: rect(1px,1px,1px,1px); } .webuploader-pick {  position: relative;  display: inline-block;  cursor: pointer;  background: #00b7ee;  padding: 6px 15px;  color: #fff;  text-align: center;  border-radius: 3px;  overflow: hidden; } .webuploader-pick-hover {  background: #00a2d4; } .webuploader-pick-disable {  opacity: 0.6;  pointer-events:none; } .file-list{  width: 100%; }</style> 

二、导出组件

var fileUpload = require('./src/file_upload.vue');module.exports = { fileUpload} 

三、demo  引用方式

<template> <div>  <el-card class="box-card">   <fileUpload ref="fileUpload" :ext="ext" :countLimit="5" :tip="tip">aaa</fileUpload>  </el-card> </div></template><script> import {fileUpload} from '@/components/fileUpload/index.js' export default{  name: 'hello',  components: {fileUpload},  data(){   return{    fileList: [],    ext: 'png,jpg,jpeg,mp3,mp4,pdf',    tip: '可上传png/jpg/jpeg/mp3/mp4/pdf,大小不超过200M'   }  },  created(){  },  methods: {   getFileList: function(){    this.fileList = this.$refs.fileUpload.getFileList();    console.log(this.fileList);   }  } }</script> 

四、运行效果图

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表