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+css实现图片滚动效果(附源码)
Mar 18 Javascript
当达到输入长度时表单自动切换焦点
Apr 06 Javascript
20条学习javascript的编程规范的建议
Nov 28 Javascript
JS中生成随机数的用法及相关函数
Jan 09 Javascript
Bootstrap按钮功能之查询按钮和重置按钮
Oct 26 Javascript
微信小程序如何获知用户运行小程序的场景教程
May 17 Javascript
react native带索引的城市列表组件的实例代码
Aug 08 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
Sep 12 Javascript
Vue组件之全局组件与局部组件的使用详解
Oct 09 Javascript
javascript和php使用ajax通信传递JSON的实例
Aug 21 Javascript
webpack结合express实现自动刷新的方法
May 07 Javascript
JavaScript 声明私有变量的两种方式
Feb 05 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
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
关于Appserv无法打开localhost问题的解决方法
2009/10/16 PHP
用PHP的超级变量$_GET获取HTML表单(Form) 数据
2011/05/07 PHP
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
2007/09/04 Javascript
javascript Select标记中options操作方法集合
2008/10/22 Javascript
js表数据排序 sort table data
2009/02/18 Javascript
javascript sudoku 数独智力游戏生成代码
2010/03/27 Javascript
ExtJs使用总结(非常详细)
2012/03/22 Javascript
js操作textarea 常用方法总结
2012/12/03 Javascript
用jquery修复在iframe下的页面锚点失效问题
2014/08/22 Javascript
JavaScript中对象property的删除方法介绍
2014/12/30 Javascript
javascript中定义类的方法详解
2015/02/10 Javascript
Js实现无刷新删除内容
2015/04/29 Javascript
Jquery中的$.each获取各种返回类型数据的使用方法
2015/05/03 Javascript
基于javascript实现tab选项卡切换特效调试笔记
2016/03/30 Javascript
addeventlistener监听scroll跟touch(实例讲解)
2017/08/04 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
2017/08/14 Javascript
在Swiper内如何制作CSS3动画效果示例代码
2017/12/07 Javascript
详解vue项目中如何引入全局sass/less变量、function、mixin
2018/06/02 Javascript
使用vue打包时vendor文件过大或者是app.js文件很大的问题
2018/06/29 Javascript
深入了解JavaScript 私有化
2019/05/30 Javascript
Vue 刷新当前路由的实现代码
2019/09/26 Javascript
在Python中利用Into包整洁地进行数据迁移的教程
2015/03/30 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
2017/09/24 Python
Django实现后台上传并显示图片功能
2020/05/29 Python
Python 程序员必须掌握的日志记录
2020/08/17 Python
CSS3实现翘边的阴影效果的代码示例
2016/06/13 HTML / CSS
德国隐形眼镜店:LuckyLens
2018/07/29 全球购物
俄罗斯领先的移动和数字设备在线商店:Svyaznoy.ru
2020/12/21 全球购物
餐饮业会计岗位职责
2013/12/19 职场文书
珍珠鸟教学反思
2014/02/01 职场文书
行政工作试用期自我评价
2014/09/14 职场文书
党员公开承诺书(2016最新版)
2016/03/24 职场文书
导游词之无锡古运河
2019/11/14 职场文书
Linux磁盘管理方法介绍
2022/06/01 Servers
Python加密与解密模块hashlib与hmac
2022/06/05 Python