背景
由于我司业务关系,需实现兼容IE8+浏览器的视频上传功能,且支持多选断点上传。故借助Baidu WebFE(FEX)团队开发的webuploader文件上传插件实现此业务功能。
一、引用
文件上传引用分为2种
(1)、script 引用 http://cdn.staticfile.org/webuploader/0.1.0/webuploader.js
(2)、npm 引用 npm install WebUploader
二、控件初始化配置
let uploaderOptions = {
//设置为 true 后,不需要手动调用上传,有文件选择即开始上传。[默认值:false] [可选]
auto: true,
//flash 上传控件地址
swf:'//static1.bitautoimg.com/web-component/yiche-upload-pc/js/Uploader.swf',
// // 上传服务器地址
server: "视频上传服务器地址",
//上传是添加自定义参数
formData: {},
//是否已二进制的流的方式发送文件,这样整个上传内容
sendAsBinary: false,
//自定义请求头
headers:{},
// 超时时间
timeout: 360000,
//{int} [可选] [默认值:undefined] 验证文件总数量, 超出则不允许加入队列。
fileNumLimit: 10,
//[可选] [默认值:undefined] 指定Drag And Drop拖拽的容器,如果不指定,则不启动。
dnd: '',
//[可选] [默认值:false] 是否禁掉整个页面的拖拽功能,如果不禁用,图片拖进来的时候会默认被浏览器打开。
disableGlobalDnd: false,
//[可选] [默认值:undefined] 指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body.
paste: document.body,
// 如果要分片,分多大一片? 默认大小为5M.
chunkSize: 1 * 1024 * 1024,
// 验证单个文件大小是否超出限制, 超出则不允许加入队列 默认: 2M
fileSingleSizeLimit: 2 * 1024 * 1024,
//是否要分片处理大文件上传。
chunked: true,
//[默认值:POST] 文件上传方式,POST 或者 GET。
method:'POST',
accept: {
title: 'videos',
//图片后缀
extensions: "mp4","rmvb","avi","flv","mov",
//匹配格式
mimeTypes: 'video/*'
},
//[可选] [默认值:undefined] 去重, 根据文件名字、文件大小和最后修改时间来生成hash Key
duplicate:true,
//不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: false,
//[可选] [默认值:false] 是否允许在文件传输时提前把下一个文件准备好。 对于一个文件的准备工作比较耗时,比如图片压缩,md5序列化。 如果能提前在当前文件传输期处理,可以节省总体耗时。
prepareNextFile: true,
//上传线程并发数为 3
threads: 3,
//设置文件上传域的name
fileVal:''
}
let uploader = new WebUploader.Uploader(uploaderOptions)
初始化参数说明
属性名称 | 说明 |
---|---|
dnd | {Selector} [可选] [默认值:undefined] 指定Drag And Drop拖拽的容器,如果不指定,则不启动。 |
disableGlobalDnd | {Selector} [可选] [默认值:false] 是否禁掉整个页面的拖拽功能,如果不禁用,图片拖进来的时候会默认被浏览器打开。 |
paste | {Selector} [可选] [默认值:undefined] 指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为 |
pick | {Selector, Object} [可选] [默认值:undefined] 指定选择文件的按钮容器,不指定则不创建按钮。
|
accept | {Array} [可选] [默认值:null] 指定接受哪些类型的文件。 由于目前还有ext转mimeType表,所以这里需要分开指定。
|
thumb | {Object} [可选] 配置生成缩略图的选项。 默认为: |
compress | {Object} [可选] 配置压缩的图片的选项。如果此选项为 |
auto | {Boolean} [可选] [默认值:false] 设置为 true 后,不需要手动调用上传,有文件选择即开始上传。 |
runtimeOrder | {Object} [可选] [默认值:html5,flash] 指定运行时启动顺序。默认会先尝试 html5 是否支持,如果支持则使用 html5, 否则使用 flash. 可以将此值设置成 |
prepareNextFile | {Boolean} [可选] [默认值:false] 是否允许在文件传输时提前把下一个文件准备好。 某些文件的准备工作比较耗时,比如图片压缩,md5序列化。 如果能提前在当前文件传输期处理,可以节省总体耗时。 |
chunked | {Boolean} [可选] [默认值:false] 是否要分片处理大文件上传。 |
chunkSize | {Boolean} [可选] [默认值:5242880] 如果要分片,分多大一片? 默认大小为5M. |
chunkRetry | {Boolean} [可选] [默认值:2] 如果某个分片由于网络问题出错,允许自动重传多少次? |
chunkRetryDelay | {Number} [可选] [默认值:1000] 开启重试后,设置重试延时时间, 单位毫秒。默认1000毫秒,即1秒. |
threads | {Boolean} [可选] [默认值:3] 上传并发数。允许同时最大上传进程数。 |
formData | {Object} [可选] [默认值:{}] 文件上传请求的参数表,每次发送都会发送此对象中的参数。 |
fileVal | {Object} [可选] [默认值:'file'] 设置文件上传域的name。 |
method | {Object} [可选] [默认值:POST] 文件上传方式,POST 或者 GET 。 |
sendAsBinary | {Object} [可选] [默认值:false] 是否已二进制的流的方式发送文件,这样整个上传内容 |
fileNumLimit | {int} [可选] [默认值:undefined] 验证文件总数量, 超出则不允许加入队列。 |
fileSizeLimit | {int} [可选] [默认值:undefined] 验证文件总大小是否超出限制, 超出则不允许加入队列。 |
fileSingleSizeLimit | {int} [可选] [默认值:undefined] 验证单个文件大小是否超出限制, 超出则不允许加入队列。 |
duplicate | {Boolean} [可选] [默认值:undefined] 去重, 根据文件名字、文件大小和最后修改时间来生成hash Key. |
disableWidgets | {String, Array} [可选] [默认值:undefined] 默认所有 Uploader.register 了的 widget 都会被加载,如果禁用某一部分,请通过此 option 指定黑名单。 |
三、初始化完配置就要添加文件了
//添加上传队列
uploader.addFiles(videoList)
四、监听上传文件事件
(1)在上传文件前,创建上传文件唯一值
//当文件被加入队列之前触发,此事件的handler返回值为false,则此文件不会被添加进入队列
uploader.on('beforeFileQueued',function(file){
//创建唯一的文件GUID标识
file.guid = createGuid()
return true
})
(2) 在上传文件前,组装分片配置
//每次上传前,如果分块传输,则带上分块信息参数
uploader.on('uploadBeforeSend',function(block, data, headers) {
var deferred = WebUploader.Deferred();
//删除无用默认属性
delete data.id
delete data.name
delete data.type
delete data.lastModifiedDate
delete data.size
delete data.chunks
delete data.chunk
delete data.file
//当前分片索引 从1开始
data.shardIndex = block.chunk + 1
//总计分片数量
data.shardTotal = block.chunks
//上传单片内容
data.shard = block.blob.source
//文件名
data.name = getFileName(block.file.name)
//文件后缀
data.suffix = getFileSuffix(block.file.name)
//文件总大小
data.size = block.file.size
//分片大小(固定值)
data.shardSize = that.options.chunkSize * 1024 * 1024
//用途
data.use = '视频上传'
//UUID 唯一值区分
data.key = block.file.guid
deferred.resolve();
})
(3)自定义分片规则
/**
* startUpload(如秒传(后台通过文件的md5判断返回)秒传则触发UploadSkip) ==> uploadStart ==> uploadBeforeSend ==> uploadProgress ==> uploadAccept(接收服务器处理分块传输后的返回信息) ==> uploadSuccess ==> uploadComplete ==> uploadFinished*/
//当有文件被添加进队列的时候
uploader.on("fileQueued", function (file) {
//获取分片规则
let chunkSize = getChunkSize(file.size)
//如果分片等于0不分片
if(chunkSize > 0){
//设置上传控件分配
uploader.options.chunkSize = chunkSize
}
//是否分片
uploader.options.chunked = chunkSize > 0;
})
(4)监听上传进度
/**
* 上传过程中触发,携带上传进度。
*/
uploader.on('uploadProgress',function(file, percentage){
//修改上传状态逻辑
var id = file.id
var $current = that.$videoList.find(`#${file.identify}`)
if(!$current) return
//文件名称
let title = file.name
//封面图地址
let src = ''
//视频唯一值
let guid = file.guid
//列表标识
let identify = file.identify
//进度
let progress = (percentage * 100).toFixed(0)
//状态
let status = 0
var html = miniTpl(createVideoLi(),{ id, src, title, guid, identify,progress, status})
$current.html(html)
})
(5)上传完成监听事件
/**
* 当文件上传成功时触发。
*/
that.uploader.on('uploadSuccess', function(file, serverData){
var id = file.id
var $current = that.$videoList.find(`#${file.identify}`)
//文件名称
var title = file.name
//视频唯一值
var guid = file.guid
//列表标识
let identify = file.identify
//进度100
var progress = 100
//封面地址
var src = ''
//文件上传状态
var status = serverData.status ? 1 : 0
//var html = yicheUtils.miniTpl(createVideoLi(),{ id, src, title, guid, identify, progress, status })
//更新文件列表
that.updateVideo(identify, { status, progress })
//$current.html(html)
that.upIndex++
if(that.upIndex == that.options.videoList.length){
//清上传索引
that.upIndex = 0
}
})
(6)上传错误处理
/*
* 当文件上传出错时触发。
*/
uploader.on('uploadError',function(file){
var id = file.id
var $current = that.$videoList.find(`#${file.identify}`)
var title = file.name
var src = ''
var progress = 0
var status = -1
var guid = file.guid
//列表标识
let identify = file.identify
var html = miniTpl(createVideoLi(),{ id, src, title, guid, identify, progress, status })
$current.html(html)
//更新视频集合
that.updateVideo(identify, { status: 0 })
})
(7)控件错误验证
/**
* 当validate不通过时,会以派送错误事件的形式通知调用者。通过
*/
uploader.on('error',function(type){
var error = ''
if (type == "Q_TYPE_DENIED") {
error = '请上传'+ that.options.videoFormat.join(',') +'格式文件'
} else if(type == "F_EXCEED_SIZE"){
error = '文件大小不能超过'+ fileSizeUnit(that.options.fileSizeLimit)
} else if(type == "Q_EXCEED_NUM_LIMIT"){
error = '上传文件最多插入'+ that.options.fileNumLimit +'个视频'
}
//提示层
that.toast(error)
})
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
//时间点1:所有分块进行上传之前调用此函数
"before-send-file" : "beforeSendFile",
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
"before-send" : "beforeSend",
//时间点3:所有分块上传成功后调用此函数
"after-send-file" : "afterSendFile",
}
事件名 | 参数说明 | 描述 |
---|---|---|
dndAccept |
| 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API,且只能通过 mime-type 验证。 |
beforeFileQueued |
| 当文件被加入队列之前触发。如果此事件handler的返回值为 |
fileQueued |
| 当文件被加入队列以后触发。 |
filesQueued |
| 当一批文件添加进队列以后触发。 |
fileDequeued |
| 当文件被移除队列后触发。 |
reset | 当 uploader 被重置的时候触发。 | |
startUpload | 当开始上传流程时触发。 | |
stopUpload | 当开始上传流程暂停时触发。 | |
uploadFinished | 当所有文件上传结束时触发。 | |
uploadStart |
| 某个文件开始上传前触发,一个文件只会触发一次。 |
uploadBeforeSend |
| 当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。 |
uploadAccept |
| 当某个文件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为 |
uploadProgress |
| 上传过程中触发,携带上传进度。 |
uploadError |
| 当文件上传出错时触发。 |
uploadSuccess |
| 当文件上传成功时触发。 |
uploadComplete |
| 不管成功或者失败,文件上传完成时触发。 |
error |
| 当validate不通过时,会以派送错误事件的形式通知调用者。通过
|
至此视频上传功能,基本能实现。