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 相关文章推荐
最新优化收藏到网摘代码(digg,diigo)
Feb 07 Javascript
js中settimeout方法加参数的使用实例
Feb 27 Javascript
浅谈jQuery中setInterval()方法
Jul 07 Javascript
jQuery实现的多滑动门,多选项卡效果代码
Mar 28 Javascript
js实现表单及时验证功能 用户信息立即验证
Sep 13 Javascript
使用JS代码实现点击按钮下载文件
Nov 12 Javascript
EditPlus 正则表达式 实战(3)
Dec 15 Javascript
Bootstrap入门教程一Hello Bootstrap初识
Mar 02 Javascript
vue router仿天猫底部导航栏功能
Oct 18 Javascript
使用 vue 实例更好的监听事件及vue实例的方法
Apr 22 Javascript
如何封装Vue Element的table表格组件
Feb 06 Vue.js
vue/cli 配置动态代理无需重启服务的方法
May 20 Vue.js
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
深入PHP异步执行的详解
2013/06/03 PHP
分享下php5类中三种数据类型的区别
2015/01/26 PHP
如何直接访问php实例对象中的private属性详解
2017/10/12 PHP
PHP有序表查找之二分查找(折半查找)算法示例
2018/02/09 PHP
WordPress JQuery处理沙发头像
2009/06/22 Javascript
JavaScript 弹出窗体点击按钮返回选择数据的实现
2010/04/01 Javascript
javascript onmouseout 解决办法
2010/07/17 Javascript
收集的10个免费的jQuery相册
2011/02/26 Javascript
Underscore.js 的模板功能介绍与应用
2012/12/24 Javascript
js中for in的用法示例解析
2013/12/25 Javascript
jQuery $命名冲突解决方案汇总
2014/11/13 Javascript
jQuery使用CSS()方法给指定元素同时设置多个样式
2015/03/26 Javascript
测试IE浏览器对JavaScript的AngularJS的兼容性
2015/06/19 Javascript
Javascript中的数据类型之旅
2015/10/18 Javascript
JQuery学习总结【二】
2016/12/01 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
2017/11/22 Javascript
详解vue 动态加载并注册组件且通过 render动态创建该组件
2019/05/30 Javascript
javascript中的相等操作符(==与===区别)
2019/12/21 Javascript
javascript实现文字跑马灯效果
2020/06/18 Javascript
python实现将内容分行输出
2015/11/05 Python
对python中的argv和argc使用详解
2018/12/15 Python
Python pycharm 同时加载多个项目的方法
2019/01/17 Python
Python 字符串、列表、元组的截取与切片操作示例
2019/09/17 Python
解决keras backend 越跑越慢问题
2020/06/18 Python
python创建文本文件的简单方法
2020/08/30 Python
马来西亚网上美容店:Hermo.my
2017/11/25 全球购物
商务英语专业毕业生自荐信
2013/11/05 职场文书
关于毕业的广播稿
2014/01/10 职场文书
班级聚会策划书
2014/01/16 职场文书
学校招生宣传广告词
2014/03/19 职场文书
弘扬雷锋精神演讲稿
2014/05/10 职场文书
2015年新学期寄语
2015/02/26 职场文书
研究生论文答辩开场白
2015/05/27 职场文书
2015年教师国培感言
2015/08/01 职场文书
教你用Python+selenium搭建自动化测试环境
2021/06/18 Python
mysql查看表结构的三种方法总结
2022/07/07 MySQL