第一步:引入第三方js和css
简单粗暴,直接在index.html文件中引入
<!--js文件-->
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/webuploader.min.js"></script>
<!--css文件-->
<link rel="stylesheet" type="text/css" href="/static/css/webuploader.css">
注意:也可通过安装依赖的方式,引入jquery插件
npm install jquery --save
import $ from 'jquery'
第二步:基于webuploader封装Vue组件
封装好的组件uploader.vue如下,接口可以根据具体的业务进行扩展。
注意:功能和ui分离,此组建封装好了基本的功能,没有提供ui,ui在具体的页面上去实现。
<template>
<div class="demo">
<div id="uploader">
<div class="queueList">
<div id="dndArea" class="placeholder">
<div id="filePicker"></div>
<p>支持截图复制进来上传</p>
</div>
</div>
<div class="statusBar" style="display:none;">
<div class="progress">
<span class="text">0%</span>
<span class="percentage"></span>
</div>
<div class="info"></div>
<div class="btns">
<div id="filePicker2"></div><div class="uploadBtn">开始上传</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 上传地址
uploadUrl: process.env.BASE_API + '/File/UploadFile',
$wrap: undefined,
$queue: undefined,
// 状态栏,包括进度和控制按钮
$statusBar: undefined,
// 文件总体选择信息。
$info: undefined,
// 上传按钮
$upload: undefined,
// 没选择文件之前的内容。
$placeHolder: undefined,
$progress: undefined,
// 添加的文件数量
fileCount: 0,
// 添加的文件总大小
fileSize: 0,
// 优化retina, 在retina下这个值是2
ratio: undefined,
// 缩略图大小
thumbnailWidth: undefined,
thumbnailHeight: undefined,
// 可能有pedding, ready, uploading, confirm, done.
state: 'pedding',
percentages: {},
// 判断浏览器是否支持图片的base64
isSupportBase64: undefined,
// 检测是否已经安装flash,检测flash的版本
flashVersion: undefined,
supportTransition: undefined,
uploader: undefined,
fileList: undefined,
fileData: {
refId: undefined,
projectId: undefined
}
}
},
mounted() {
this.init()
this.initWebUploader()
this.fileData.refId = this.refId
this.fileData.projectId = this.projectId
this.clearFileList()
this.getFileList()
},
props: {
projectId: String,
systemTime: Number,
refId: String
},
methods: {
init() {
this.$wrap = $('#uploader')
// 图片容器
this.$queue = $('<ul class="filelist"></ul>').appendTo(this.$wrap.find('.queueList'))
// 状态栏,包括进度和控制按钮
this.$statusBar = this.$wrap.find('.statusBar')
// 文件总体选择信息。
this.$info = this.$statusBar.find('.info')
// 上传按钮
this.$upload = this.$wrap.find('.uploadBtn')
// 没选择文件之前的内容。
this.$placeHolder = this.$wrap.find('.placeholder')
this.$progress = this.$statusBar.find('.progress').hide()
// 添加的文件数量
this.fileCount = 0
// 添加的文件总大小
this.fileSize = 0
// 优化retina, 在retina下这个值是2
this.ratio = window.devicePixelRatio || 1
// 缩略图大小
this.thumbnailWidth = 110 * this.ratio
this.thumbnailHeight = 110 * this.ratio
// 可能有pedding, ready, uploading, confirm, done.
this.state = 'pedding'
// 所有文件的进度信息,key为file id
this.percentages = {}
// // 判断浏览器是否支持图片的base64
this.isSupportBase64 = (function() {
var data = new Image()
var support = true
data.onload = data.onerror = function() {
if (this.width != 1 || this.height != 1) {
support = false
}
}
data.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
return support
})()
// 检测是否已经安装flash,检测flash的版本
this.flashVersion = (function() {
var version
try {
version = navigator.plugins[ 'Shockwave Flash' ]
version = version.description
} catch (ex) {
try {
version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')
.GetVariable('$version')
} catch (ex2) {
version = '0.0'
}
}
version = version.match(/\d+/g)
return parseFloat(version[ 0 ] + '.' + version[ 1 ], 10)
})()
this.supportTransition = (function() {
var s = document.createElement('p').style,
r = 'transition' in s ||
'WebkitTransition' in s ||
'MozTransition' in s ||
'msTransition' in s ||
'OTransition' in s
s = null
return r
})()
},
// 初始化webuploader
initWebUploader() {
var that = this
if (!WebUploader.Uploader.support('flash') && WebUploader.browser.ie) {
// flash 安装了但是版本过低。
if (that.flashVersion) {
(function(container) {
window['expressinstallcallback'] = function(state) {
switch (state) {
case 'Download.Cancelled':
alert('您取消了更新!')
break
case 'Download.Failed':
alert('安装失败')
break
default:
alert('安装已成功,请刷新!')
break
}
delete window['expressinstallcallback']
}
var swf = './expressInstall.swf'
// insert flash object
var html = '<object type="application/' +
'x-shockwave-flash" data="' + swf + '" '
if (WebUploader.browser.ie) {
html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '
}
html += 'width="100%" height="100%" style="outline:0">' +
'<param name="movie" value="' + swf + '" />' +
'<param name="wmode" value="transparent" />' +
'<param name="allowscriptaccess" value="always" />' +
'</object>'
container.html(html)
})(that.$wrap)
// 压根就没有安转。
} else {
that.$wrap.html('<a href="http://www.adobe.com/go/getflashplayer" target="_blank" border="0"><img alt="get flash player" src="http://www.adobe.com/macromedia/style_guide/images/160x41_Get_Flash_Player.jpg" /></a>')
}
return
} else if (!WebUploader.Uploader.support()) {
alert('Web Uploader 不支持您的浏览器!')
return
}
// 实例化
that.uploader = WebUploader.create({
pick: {
id: '#filePicker',
label: '点击选择附件'
},
formData: {
refId: undefined,
projectId: undefined
},
dnd: '#dndArea',
paste: '#uploader',
swf: '../../../static/js/Uploader.swf',
chunked: false,
chunkSize: 512 * 1024,
server: that.uploadUrl,
// 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
disableGlobalDnd: true,
fileNumLimit: 10,
fileSizeLimit: 10 * 1024 * 1024, // 200 M
fileSingleSizeLimit: 5 * 1024 * 1024 // 50 M
})
// 拖拽时不接受 js, txt 文件。
that.uploader.on('dndAccept', function(items) {
var denied = false
const len = items.length
var i = 0
// 修改js类型
var unAllowed = 'text/plain;application/javascript '
for (; i < len; i++) {
// 如果在列表里面
if (~unAllowed.indexOf(items[ i ].type)) {
denied = true
break
}
}
return !denied
})
// 文件发送前
that.uploader.on('uploadBeforeSend', function(file, data) {
data.refId = that.refId
data.projectId = that.projectId
})
// 进度条
that.uploader.on('uploadProgress', function(file, percentage) {
var $li = $('#' + file.id)
var $percent = $li.find('.progress span')
$percent.css('width', percentage * 100 + '%')
that.percentages[ file.id ][ 1 ] = percentage
that.updateTotalProgress()
})
// 当文件被加入队列以后触发
that.uploader.on('fileQueued', (file) => {
that.fileCount++
that.fileSize += file.size
if (that.fileCount === 1) {
that.$placeHolder.addClass('element-invisible')
that.$statusBar.show()
}
that.addFile(file)
that.setState('ready')
that.updateTotalProgress()
})
// 当文件被移除队列后触发
that.uploader.on('fileDequeued', (file) => {
that.fileCount--
that.fileSize -= file.size
if (!that.fileCount) {
that.setState('pedding')
}
that.removeFile(file)
that.updateTotalProgress()
})
//文件上传完成后触发
that.uploader.on('uploadFinished', function(type) {
that.setState('confirm')
})
//文件开始上传时触发
that.uploader.on('startUpload', function(type) {
that.setState('uploading')
})
// 文件暂停上传时触发
that.uploader.on('stopUpload', function(type) {
that.setState('paused')
})
//文件上传出错后触发
that.uploader.on('error', function(code) {
var errMsg
switch (code) {
case 'F_EXCEED_SIZE':
errMsg = '文件大小超出'
break
case 'interrupt':
errMsg = '上传暂停'
break
default:
errMsg = '上传失败,请重试'
break
}
that.$message({
message: errMsg,
type: 'error'
})
})
that.$upload.on('click', function() {
if ($(that).hasClass('disabled')) {
return false
}
if (that.state === 'ready') {
that.uploader.upload()
} else if (that.state === 'paused') {
that.uploader.upload()
} else if (that.state === 'uploading') {
that.uploader.stop()
}
})
that.$info.on('click', '.retry', function() {
that.uploader.retry()
})
that.$info.on('click', '.ignore', function() {
alert('todo')
})
that.$upload.addClass('state-' + that.state)
that.updateTotalProgress()
},
addFile(file) {
var that = this
var $li = $('<li id="' + file.id + '">' +
'<p class="title">' + file.name + '</p>' +
'<p class="imgWrap"></p>' +
'<p class="progress"><span></span></p>' +
'</li>')
var $btns = $('<div class="file-panel">' +
'<span class="cancel">删除</span></div>').appendTo($li)
var $prgress = $li.find('p.progress span')
var $wrap = $li.find('p.imgWrap')
var $info = $('<p class="error"></p>')
var showError = function(code) {
switch (code) {
case 'F_EXCEED_SIZE':
text = '文件大小超出'
break
case 'interrupt':
text = '上传暂停'
break
default:
text = '上传失败,请重试'
break
}
$info.text(text).appendTo($li)
}
if (file.getStatus() === 'invalid') {
showError(file.statusText)
} else {
// @todo lazyload
$wrap.text('预览中')
that.uploader.makeThumb(file, function(error, src) {
var img
if (error) {
$wrap.text('不能预览')
return
}
// 判断浏览器是否支持图片的base64
if (that.isSupportBase64) {
img = $('<img src="' + src + '">')
$wrap.empty().append(img)
} else {
// 预览操作,根据实际情况
$.ajax('../preview.action', {
method: 'POST',
data: src,
dataType: 'json'
}).done(function(response) {
if (response.result) {
img = $('<img src="' + response.result + '">')
$wrap.empty().append(img)
} else {
$wrap.text('预览出错')
}
})
}
}, that.thumbnailWidth, that.thumbnailHeight)
that.percentages[ file.id ] = [file.size, 0]
file.rotation = 0
}
file.on('statuschange', function(cur, prev) {
if (prev === 'progress') {
$prgress.hide().width(0)
} else if (prev === 'queued') {
$li.off('mouseenter mouseleave')
$btns.remove()
}
// 成功
if (cur === 'error' || cur === 'invalid') {
showError(file.statusText)
that.percentages[ file.id ][ 1 ] = 1
} else if (cur === 'interrupt') {
showError('interrupt')
} else if (cur === 'queued') {
that.percentages[ file.id ][ 1 ] = 0
} else if (cur === 'progress') {
$info.remove()
$prgress.css('display', 'block')
} else if (cur === 'complete') {
$li.append('<span class="success"></span>')
}
$li.removeClass('state-' + prev).addClass('state-' + cur)
})
$li.on('mouseenter', function() {
$btns.stop().animate({ height: 30 })
})
$li.on('mouseleave', function() {
$btns.stop().animate({ height: 0 })
})
$li.on('click', function() {
window.open(file.source.src)
})
$btns.on('click', 'span', function() {
var index = $(this).index()
var deg
switch (index) {
case 0:
that.uploader.removeFile(file)
return
case 1:
file.rotation += 90
break
case 2:
file.rotation -= 90
break
}
if (this.supportTransition) {
deg = 'rotate(' + file.rotation + 'deg)'
$wrap.css({
'-webkit-transform': deg,
'-mos-transform': deg,
'-o-transform': deg,
'transform': deg
})
} else {
$wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')')
}
})
$li.appendTo(this.$queue)
},
removeFile(file) {
var that = this
var $li = $('#' + file.id)
delete that.percentages[ file.id ]
this.updateTotalProgress()
$li.off().find('.file-panel').off().end().remove()
if (file.source.id === undefined) {
return
}
// 删除远程文件
fileRemove(file.source.id).then(response => {
if (response.data.success) {
this.$message({
message: '删除附件成功',
type: 'success'
})
} else {
this.$message({
message: response.data.msg,
type: 'error'
})
}
})
},
updateTotalProgress() {
var that = this
var loaded = 0
var total = 0
var spans = this.$progress.children()
var percent
$.each(that.percentages, function(k, v) {
total += v[ 0 ]
loaded += v[ 0 ] * v[ 1 ]
})
percent = total ? loaded / total : 0
spans.eq(0).text(Math.round(percent * 100) + '%')
spans.eq(1).css('width', Math.round(percent * 100) + '%')
},
setState(val) {
var that = this
var stats
if (val === that.state) {
return
}
that.$upload.removeClass('state-' + that.state)
that.$upload.addClass('state-' + val)
that.state = val
switch (that.state) {
case 'pedding':
that.$placeHolder.removeClass('element-invisible')
that.$queue.show()
that.$statusBar.addClass('element-invisible')
that.uploader.refresh()
break
case 'ready':
that.$placeHolder.addClass('element-invisible')
$('#filePicker2').removeClass('element-invisible')
that.$queue.show()
that.$statusBar.removeClass('element-invisible')
that.uploader.refresh()
break
case 'uploading':
$('#filePicker2').addClass('element-invisible')
that.$progress.show()
that.$upload.text('暂停上传')
break
case 'paused':
that.$progress.show()
that.$upload.text('继续上传')
break
case 'confirm':
that.$progress.hide()
$('#filePicker2').removeClass('element-invisible')
that.$upload.text('开始上传')
stats = that.uploader.getStats()
if (stats.successNum && !stats.uploadFailNum) {
that.setState('finish')
return
}
break
case 'finish':
stats = that.uploader.getStats()
if (stats.successNum) {
// alert('上传成功')
} else {
// 没有成功的图片,重设
that.state = 'done'
location.reload()
}
break
}
},
// 清空文件列表
clearFileList() {
this.$info.empty()
this.$queue.empty()
this.fileCount = 0
this.fileSize = 0
},
// 获取已上传的文件列表
getFileList() {
this.fileList = []
if (this.fileData.projectId !== undefined && this.fileData.refId !== undefined) {
getFileList(this.fileData).then(response => {
this.fileList = this.formatUrl(response.data)
})
}
},
// 将已上传的文件加载到组件列表中
formatUrl(files) {
for (let i = 0; i < files.length; i++) {
files[i].url = process.env.BASE_API + files[i].url
const obj = {}
obj.name = files[i].name
obj.size = files[i].size
obj.lastModifiedDate = item.createTime
obj.id = files[i].Id
obj.src = files[i].url
obj.ext = item.fileType.substr(1)
var file = new WebUploader.File(obj)
// 此处是关键,将文件状态改为'已上传完成'
file.setStatus('complete')
this.addFile(file)
}
return files
}
},
watch: {
systemTime() {
this.fileData.refId = this.refId
this.fileData.projectId = this.projectId
this.clearFileList()
this.getFileList()
}
}
}
</script>
第三步:组件引用
在vue项目中引入开发好的组件,需要三步
<!-- 1、引入组件 -->
import vueUploader from '@/components/common/uploader.vue'
<!-- 2、注册组件-->
components: {
vueUploader
},
<!-- 3、使用组件 -->
<vue-uploader :projectId='undefined' :refId='undefined' :systemTime="this.systemTime"></vue-uploader>
网友评论