vue webuploader 文件上传组件开发


Posted in Javascript onSeptember 23, 2017

最近项目中需要用到百度的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>

四、运行效果图

vue webuploader 文件上传组件开发

vue webuploader 文件上传组件开发

vue webuploader 文件上传组件开发

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的关于动态创建DOM元素的问题
Dec 24 Javascript
jquery键盘事件介绍
Jan 31 Javascript
jQuery.query.js 取参数的两点问题分析
Aug 06 Javascript
浅谈关于JavaScript API设计的一些建议和准则
Jun 24 Javascript
全面解析Bootstrap表单使用方法(表单样式)
Nov 24 Javascript
js表单登陆验证示例
Oct 19 Javascript
浅谈vue-router 路由传参的方法
Dec 27 Javascript
详解创建自定义的Angular Schematics
Jun 06 Javascript
Vue中 key keep-alive的实现原理
Sep 18 Javascript
Vue 实现一个命令式弹窗组件功能
Sep 25 Javascript
Vue Cli3 打包配置并自动忽略console.log语句的方法
Apr 23 Javascript
vue-iview动态新增和删除的方法
Jun 17 Javascript
jQuery使用zTree插件实现可拖拽的树示例
Sep 23 #jQuery
一个有意思的鼠标点击文字特效jquery代码
Sep 23 #jQuery
JQuery用$.ajax或$.getJSON跨域获取JSON数据的实现代码
Sep 23 #jQuery
VsCode新建VueJs项目的详细步骤
Sep 23 #Javascript
详解webpack + vue + node 打造单页面(入门篇)
Sep 23 #Javascript
JavaScript定义函数的三种实现方法
Sep 23 #Javascript
angular.js4使用 RxJS 处理多个 Http 请求
Sep 23 #Javascript
You might like
预告映像公开!第1章续篇剧场版动画《Princess Principal Crown Handler》4月10日上映!
2020/03/06 日漫
在同一窗体中使用PHP来处理多个提交任务
2008/05/08 PHP
无刷新动态加载数据 滚动条加载适合评论等页面
2013/10/16 PHP
PHP命令行脚本接收传入参数的三种方式
2014/08/20 PHP
php判断是否为ajax请求的方法
2016/11/29 PHP
PHP使用栈解决约瑟夫环问题算法示例
2017/08/27 PHP
Laravel 队列使用的实现
2019/01/08 PHP
IE6下JS动态设置图片src地址问题
2010/01/08 Javascript
javascript 词法作用域和闭包分析说明
2010/08/12 Javascript
浅谈Javascript嵌套函数及闭包
2010/11/09 Javascript
jquery实现文字由下到上循环滚动的实例代码
2013/08/09 Javascript
jsonp原理及使用
2013/10/28 Javascript
js给onclick赋值传参数的两种方法
2013/11/25 Javascript
js对象转json数组的简单实现案例
2014/02/28 Javascript
js实现div闪烁原理及实现代码
2014/06/24 Javascript
使用jquery.upload.js实现异步上传示例代码
2014/07/29 Javascript
jQuery使用addClass()方法给元素添加多个class样式
2015/03/26 Javascript
Javascript对象Clone实例分析
2015/06/09 Javascript
浅谈EasyUI常用控件的禁用方法
2016/11/09 Javascript
基于Express框架使用POST传递Form数据
2019/08/10 Javascript
解决VUE-Router 同一页面第二次进入不刷新的问题
2020/07/22 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
[02:55]DOTA2英雄基础教程 发条技师
2013/12/04 DOTA
使用Python编写一个在Linux下实现截图分享的脚本的教程
2015/04/24 Python
分享一下Python 开发者节省时间的10个方法
2015/10/02 Python
Python 中urls.py:URL dispatcher(路由配置文件)详解
2017/03/24 Python
解决Python获取字典dict中不存在的值时出错问题
2018/10/17 Python
python机器学习库scikit-learn:SVR的基本应用
2019/06/26 Python
CSS3 rgb and rgba(透明色)的使用详解
2020/09/25 HTML / CSS
康拓普公司Java笔面试
2016/09/23 面试题
公司捐款倡议书
2014/05/14 职场文书
合作经营协议书范本
2014/09/16 职场文书
员工2014年度工作总结
2014/12/09 职场文书
会议主持词开场白
2015/05/28 职场文书
2015年入党积极分子培养考察意见
2015/08/12 职场文书
Python Pandas常用函数方法总结
2021/06/15 Python