Vue 封装文件上传组件
大龙BBG 人气:0前言
在面向特定用户的项目中,引 其他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) { //
加载全部内容
- 猜你喜欢
- 用户评论