1、概述
【是什么】上传组件 upload 是用于处理文件上传的前端交互逻辑,可以更好地协助后端实现文件从本地到服务端上传的对接。
【版本】v2.0 开始支持。
2、示例
制作多文件上传表格
先选择文件,列表展示上传任务(可删除),最后点击按钮确定上传。
3、API
upload 模块
var upload = layui.upload 获得 upload 模块。
upload.render()
/**
* @brief: upload 组件渲染,核心方法。
* @param {object} options 基础属性配置项 (见下面 “options 参数”)
* @return {object} inst 返回一个实例对象,包含操作当前实例的相关方法成员
*/
const inst = upload.render(options)
inst.upload()
/**
* @brief: 对当前实例提交上传
* 【场景】文件在进行选择后,默认会自动提交上传。而若文件上传失败,则可以使用该方法来重新上传。
* 无参
* @return {*}
*/
inst.upload()
inst.reload(options)
/**
* @brief: 完整重载
* 【场景】该方法用于对当前的上传实例进行完整重载,所有属性均可参与到重载中。
* @param {object} options:基础属性配置项(同.render配置项)
* @return {*}
*/
inst.reload(options)
// d1
inst.reload({
field: 'AAA',
// ...
})
inst.config
{object} 获得当前实例的属性配置项。
接口返回要求
【要求】必须是一个标准的 JSON 格式。
【示例】建议返回格式
{
"code": 0,
"msg": "",
"data": {
"src": "http://cdn.layui.com/123.jpg",
}
}
【注意 1】你不一定非得按照上述格式返回,只要是合法的 JSON 字符即可。其响应信息会转化成 JS 对象传递给 done 回调
。
【注意 2】如果上传后,出现文件下载框(一般为 ie 下),那么你需要在服务端对 response 的 header 设置 Content-Type: text/html
(IE11 并没有出现)
4、options 参数
elem
【描述】绑定元素选择器 或 DOM 对象
【类型】{string|DOM}
【默认值】-
url
【描述】上传接口
【类型】{string}
【默认值】-
field
【描述】文件域的字段名 (即 ajax 提交时 formData 保存文件的字段名)
【类型】{string}
【默认值】file
data
【描述】传递给上传接口的额外参数,支持静态赋值和动态赋值两种写法。
【类型】{object}
【默认值】-
【静态赋值】
data: {
id: '123',
}
【动态赋值】
data: {
id: function() {
return $('#id').val()
},
id2: function(index, file) {
// !v2.9.3+ 支持
// 【注意】当 unified: true 和 ie8/9 下,参数无效。
console.log(index) // 得到文件索引
console.log(file) // 得到文件对象
}
}
headers
【描述】上传接口的请求头。
【类型】{object}
【默认值】-
dataType
【版本】v2.8.17+
【描述】服务端返回的数据类型。
【类型】{string}
【可选值】
- text
- json(def)
- xml
- 等
【默认值】‘json’
accept
【描述】指定允许上传时校验的文件类型。
【类型】{object}
【可选值】
- images 图片类型
- file 所有文件类型
- video 视频类型
- audio 音频类型
【默认值】-
acceptMime
【描述】规定打开系统的文件选择框时,筛选出的文件类型,多个 MIME 类型可用逗号隔开。
【类型】{string}
【默认值】-
【示例】
acceptMime: 'image/*'` // 筛选所有图片类型
acceptMime: 'image/jpeg, image/png` // 只筛选 jpg,png 格式图片
exts
【描述】允许上传的文件后缀。一般结合 accept 属性来设定。
【类型】{string}
【默认值】-
// 代表只允许上传压缩格式的文件。
{
accept: 'file',
exts: 'zip|rar|7z',
}
// 默认:常见图片后缀
// jpg|png|gif|bmp|jpeg|svg
auto & bindAction
【场景需求】上传后不自动上传,点击按钮后确认上传。
1、auto 值为 false 时,为配置不自动上传,上传流程中断在这一步。
2、非自动上传,预览图片功能,点击按钮后再继续上传/取消上传。
3、继续上传:需要 参数 bindAction 配置的按钮点击后才能继续上传;
auto
【描述】是否选完文件后自动上传。
【类型】{boolean}
【默认值】true
false: 此时需要 bindAction 属性来指向其它按钮提交上传。
bindAction
【描述】设置触发上传的元素选择器或 DOM 对象。
(一般配合 auto: false 来使用)
【类型】{string|DOM}
【默认值】-
force
【版本】v2.6.9+
【描述】规定强制返回的数据格式。
【类型】{string}
- ‘json’ 会强制校验 JSON 数据格式。
【默认值】null
size
【描述】设置文件最大可允许上传的大小,单位 KB。默认不限制。不支持 ie8/9。
【类型】{number}
【默认值】0 (不限制)
multiple
【描述】是否允许多文件上传。不支持 ie8/9。
【类型】{boolean}
【默认值】false (默认单选)
unified
【版本】v2.8.8+
【描述】选择多文件时,是否统一上传,即只发送一次请求。
【类型】{boolean}
【默认值】false (默认多文件不统一上传,会触发多次请求)
number
【描述】同时可上传的文件数量,一般当 multiple: true 时使用。
【类型】{number}
【默认值】-
drag
【描述】是否接受拖拽的文件上传。
【类型】{boolean}
【默认值】true 接受拖拽来的文件上传
text
【版本】v2.8.9+
【描述】自定义内部各类场景下的提示文本。
text: {
// 自定义提示文本
"data-format-error": "", // 数据格式错误的提示
"check-error": "", // 文件格式校验失败的提示
"error": "", // 上传失败的提示
"limit-number": null, // 限制 number 属性的提示。若设置,需为函数写法。
"limit-size": null, // 限制 size 属性的提示。若设置,需为函数写法。
"cross-domain": "", // IE 下跨域的提示
}
回调函数
choose
语法
const options = {
/**
* @brief: 文件被选择后触发的回调
* @param {object} obj:参数对象内有多个方法。(详细见下)
* @return {*}
*/
choose: function (obj) {
// 将每次选择的文件追加到文件队列
var files = obj.pushFile()
// 预读本地文件,如果是多文件,则会遍历(不支持 ie8/9)
obj.preview(function (index, file, result) {
console.log(index) // 得到文件索引
console.log(file) // 得到文件对象
console.log(result) // 得到文件base64编码,比如图片
// obj.resetFile(index, file, '123.jpg') // 重命名文件名
// 这里还可以做一些 append 文件列表 DOM 的操作
// obj.upload(index, file); // 对上传失败的单个文件重新上传,一般在某个事件中使用
// delete files[index]; // 删除列表中对应的文件,一般在某个事件中使用
})
// 获取本次选取的文件,大文件建议用此方法获取文件信息(2.9.9+)
obj.getChooseFiles()
},
}
【2 注意】
!该回调会在 before 回调之前执行。
!一般用于非自动上传(auto: false)的场景,比如先预览图片等。
obj.pushFile()
/**
* @brief: 将每次选择的文件追加到文件队列。
* @return {*} files 已选择的文件信息对象,子对象是 File 对象;(注意:可将文件信息对象保存到全局变量中 )
*/
let files = obj.pushFile()
obj.preview()
/**
* @brief: 预读本地文件。
* 【注意】若是多文件,则会遍历。(不支持 IE8/9)
* @param {function} callback(index,file,result) 遍历选中文件队列的回调
* index: 文件索引;
* file: 文件对象;
* result: 文件 base64编码(如图片);
* 【拓展】还可以做一些 append 文件列表 DOM 的操作。
* 【拓展2】删除文件 delete files[index]。
* @return {*}
*/
obj.preview(function (index, file, result) {})
obj.resetFile()
/**
* @brief: 重命名文件名(在 obj.preview 中调用)
* v2.3.0 开始新增
* @param {number} index:用索引定位需要重命名的文件
* @param {object} file:需修改文件所在的File对象
* @param {string} renamestring:重命名名称
* @return {*}
*/
obj.resetFile(index, file, renamestring)
// d
obj.resetFile(index, file, '123.jpg')
obj.upload()
/**
* @brief: 重新上传(在 obj.preview 中调用)
* 【场景】对上传失败的单个文件重新上传,一般在某个事件中使用。
* @param {number} index:用索引定位需要重命名的文件
* @param {object} file:文件对象
* @return {*}
*/
obj.upload(index, file)
obj.getChooseFiles()
/**
* @brief: 获取本次选取的文件,大文件建议用此方法获取文件信息
* v2.9.9+
* @return {*}
*/
obj.getChooseFiles()
清空上传文件队列
function clearFile(UPLOAD_FILES) {
for (var x in UPLOAD_FILES) {
delete UPLOAD_FILES[x]
}
}
// 调用1:done 回调顶部
// 调用2: error回调顶部
before
语法
const options = {
/**
* @brief: 上传前的回调
* 【触发时机】在 choose 回调之后、done/error 回调之前触发。
* @param {Object} obj 与 choose 相同
* @return {*}
*/
before: function (obj) {},
}
加载中
const options = {
before: function (obj) {
layer.load() //上传loading (需要在 done, error 中关闭 loading)
},
}
阻止上传 1 - 返回 false
const options = {
before: function (obj) {
if (true) {
return false // 阻止上传
}
},
}
阻止上传 2 - 返回 promise
// v2.9.11+
const options = {
before: function (obj) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('before_async_task', obj)
resolve(true)
}, 1000)
})
},
}
阻止上传 3-返回 jq Deferred 对象
const options = {
before: function (obj) {
return $.Deferred(function (defer) {
setTimeout(function () {
console.log('before_async_task', obj)
defer.resolve(true)
}, 1000)
}).promise()
},
// 写法2
before: function (obj) {
var defer = $.Deferred()
setTimeout(function () {
console.log('before_async_task', obj)
defer.resolve(true)
}, 1000)
return defer.promise()
},
}
经验:data 在 before 中定义
场景:在实际开发中,某些请求参数字段对应的值是动态的;(比如上传文件需传入 taskId 参数,后台根据这个 id 将文件存到数据库对应的用户下。)
问题:如果在 upload 中书写是无法传递 动态参数的;
解决:实例 demo 中任务 id 是通过 data-taskId 属性绑定在上传按钮上的, 可通过 this.item 获取触发上传按钮的 jq 元素集合,再获取其绑定的值;
而 this 需要在函数中书写,指向当前的 upload 实例;所以,该段动态参数获取可写在 before 回调中(只需要在 data-taskId 属性值再标签上绑定即可);
progress
const options = {
/**
* @brief: 文件上传进度的回调
* @param {Number} n 进度百分比数字
* @param {Object} elem 得到当前触发的元素 DOM 对象。
* @param {Object} res 得到 progress 响应信息
* @param {Number} index 得到当前上传文件的索引,用于多文件上传时的进度条控制
* @return {*}
*/
progress: function (n, elem, res, index) {
var percent = n + '%' //获取进度百分比
element.progress('demo', percent) //可配合 layui 进度条元素使用
console.log(elem) //得到当前触发的元素 DOM 对象。可通过该元素定义的属性值匹配到对应的进度条。
console.log(res) //得到 progress 响应信息
console.log(index) //得到当前上传文件的索引,多文件上传时的进度条控制,如:
element.progress('demo-' + index, n + '%') //进度条
},
}
done
const options = {
/**
* @brief: 上传接口请求成功的回调
* !上传接口请求完毕后触发,但文件不一定是上传成功的,只是接口的响应状态正常(200)。
* @param {*} res 服务端响应信息
* @param {*} index 当前文件的索引
* @param {*} upload 重新上传的方法
* @return {*}
*/
done: function (res, index, upload) {
clearFile(UPLOAD_FILES) // 清空已保存的文件信息对象
element.progress('progressBar', '0%')
$('#progressBar').css('display', 'none')
if (res.code == 0) {
// 业务处理
layer.msg('上传成功', { time: 1000 })
} else {
layer.msg(res.msg)
}
// layer.closeAll('loading'); //关闭loading
},
}
allDone
const options = {
/**
* @brief: 多文件上传完毕后的状态回调
* !当文件全部被提交后,才触发
* !只有当开启多文件时(即 multiple: true),该回调才会被触发。
* @param {Object} obj 包含一些状态数据
* {Number} total 得到总文件数
* {Number} successful 请求成功的文件数
* {Number} aborted 请求失败的文件数
* @return {*}
* #对比:done 回调,是每个文件提交一次触发一次。详见“请求成功的回调“
*/
allDone: function (obj) {
console.log(obj.total)
console.log(obj.successful)
console.log(obj.aborted)
},
}
error
const options = {
/**
* @brief: 上传请求失败的回调
* @param {Number} index 当前文件的索引
* @param {Function} upload 重新上传的方法
* @return {*}
*/
error: function (index, upload) {
layer.closeAll('loading') //关闭loading
// 【重新上传】当上传失败时,你可以生成一个“重新上传”的按钮,点击该按钮时,执行 upload() 方法即可实现重新上传
},
}
5、跨域方案
upload 组件支持跨域上传,一般有以下 2 种场景。
【场景 1】自建上传服务。在服务端配置 CORS 开启跨域资源共享。
即对接口所在的服务器设置 Access-Control-Allow-Origin
相关 header 信息。
【场景 2】第三方上传服务。
如:阿里云、腾讯云登,只需按照不同平台对应的上传 SDK 进行操作即可。