目录 前言 1. 子组件 2 父组件使用 3.效果 4.总结 前言 在面向特定用户的项目中,引 其他ui组件库导致打包体积过大,首屏加载缓慢,还需要根据UI设计师设计的样式,重写大量的样式覆
目录
- 前言
- 1. 子组件
- 2 父组件使用
- 3.效果
- 4.总结
前言
在面向特定用户的项目中,引 其他ui组件库导致打包体积过大,首屏加载缓慢,还需要根据UI设计师设计的样式,重写大量的样式覆盖引入的组件库的样式。因此尝试自己封装一个自己的组件,代码参考了好多前辈的文章
1. 子组件
<template>
<div class="digital_upload">
<input
style="display: none"
@change="addFile"
:multiple="multiple"
type="file"
:name="name"
:id="id"
:accept="accept"
/>
<label :for="id">
<slot></slot>
</label>
</div>
</template>
<script>
export default {
name: 'my-upload',
props: {
name: String,
action: {
type: String,
required: true
},
fileList: {
type: Array,
default () {
return []
}
},
accept: {
type: String,
require: true
},
id: {
type: String,
default: 'my-upload'
},
data: Object,
multiple: Boolean,
limit: Number,
onChange: Function,
onBefore: Function,
onProgress: Function,
onSuccess: Function,
onFailed: Function,
onFinished: Function
},
methods: {
// input的 chang事件处理方法
addFile ({ target: { files } }) { // input标签触发onchange事件时,将文件加入待上传列表
for (let i = 0, l = files.length; i < l; i++) {
files[i].url = URL.createObjectURL(files[i])// 创建blob地址,不然图片怎么展示?
files[i].status = 'ready'// 开始想给文件一个字段表示上传进行的步骤的,后面好像也没去用......
}
let fileList = [...this.fileList]
if (this.multiple) { // 多选时,文件全部压如列表末尾
fileList = [...fileList, ...files]
const l = fileList.length
let limit = this.limit
if (limit && typeof limit === 'number' && Math.ceil(limit) > 0 && l > limit) { // 有数目限制时,取后面limit个文件
limit = Math.ceil(limit)
// limit = limit > 10 ? 10 : limit;
fileList = fileList.slice(l - limit)
}
} else { // 单选时,只取最后一个文件。注意这里没写成fileList = files;是因为files本身就有多个元素(比如选择文件时一下子框了一堆)时,也只要一个
fileList = [files[0]]
}
this.onChange(fileList)// 调用父组件方法,将列表缓存到上一级data中的fileList属性
},
// 移除某一个文件
remove (index) {
const fileList = [...this.fileList]
if (fileList.length) {
fileList.splice(index, 1)
this.onChange(fileList)
}
},
// 检测是否可以提交
checkIfCanUpload () {
console.log(this.fileList.length)
return this.fileList.length ? ((this.onBefore && this.onBefore()) || !this.onBefore) : false
},
// 根据情况使用不同的提交的方法
submit () {
console.log('开始提交')
if (this.checkIfCanUpload()) {
// console.log('开始提交2')
if (this.onProgress && typeof XMLHttpRequest !== 'undefined') {
this.xhrSubmit()
} else {
this.fetchSubmit()
}
}
},
// fethc 提交
fetchSubmit () {
const keys = Object.keys(this.data); const values = Object.values(this.data); const action = this.action
const promises = this.fileList.map(each => {
each.status = 'uploading'
const data = new FormData()
data.append(this.name || 'file', each)
keys.forEach((one, index) => data.append(one, values[index]))
return fetch(action, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data
}).then(res => res.text()).then(res => JSON.parse(res))// 这里res.text()是根据返回值类型使用的,应该视情况而定
})
Promise.all(promises).then(resArray => { // 多线程同时开始,如果并发数有限制,可以使用同步的方式一个一个传,这里不再赘述。
let success = 0; let failed = 0
resArray.forEach((res, index) => {
if (res.code === 1) {
success++ // 统计上传成功的个数,由索引可以知道哪些成功了
this.onSuccess(index, res)
} else if (res.code === 520) { // 约定失败的返回值是520
failed++ // 统计上传失败的个数,由索引可以知道哪些失败了
this.onFailed(index, res)
}
})
return { success, failed } // 上传结束,将结果传递到下文
}).then(this.onFinished) // 把上传总结果返回
},
// xhr 提交
// xhrSubmit () {
// const _this = this
// const options = this.fileList.map((rawFile, index) => ({
// file: rawFile,
// data: _this.data,
// filename: _this.name || 'file',
// action: _this.action,
// headers: {
// Authorization: window.sessionStorage.getItem('token')
// },
// onProgress (e) {
// _this.onProgress(index, e)// 闭包,将index存住
// },
// onSuccess (res) {
// _this.onSuccess(index, res)
// },
// onError (err) {
// _this.onFailed(index, err)
// },
// onFinished (res) { // 