vue webuploader 文件上传组件开发

最近项目中需要用到百度的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&#45;&#45;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, span, 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 文件上传组件开发 的全部内容, 来源链接: utcz.com/z/360027.html

回到顶部