基于element UI封装一个上传组件
之前写了一个上传组件,最近要改成上传到云端桶里,本来只是改一个上传接口,但打开看了一眼以前写的上传组件,真的稀碎,于是重新实现一遍。
在项目中,用上传组件的大部分情况,都是picture-card
,5%的其他展示形式。所以主要是针对pictrue-card
展示形式的处理,其他的开放插槽让用的人自己细细处理。
之前的上传组件,有特别多props,在此方案中,尽量不要加props,传参理解起来需要时间,会增加使用成本,能用slot替代,就用slot。
组件构成
所以,组件计划支持
① 上传区域开插槽,支持用户使用者自定义上传区域的展示内容;若不用插槽,则展示默认的内容;默认内容支持用插槽替换局部
② 展示区域开插槽,支持用户自定义上传文件后的展示形式;若不用插槽,则展示默认的内容
③ 支持只读模式,不允许上传
④ 支持文件预览:图片用v-viewer;非弹窗打开新页面看,不支持的话浏览器会自动下载
⑤ 图片卡片模式(picture-card
)展示文件名
⑥ 基础内容和上传方法单独抽成一个js文件存放,上传组件里只放它自己的逻辑
默认内容介绍:
默认使用加号的图标,带插槽uploadText
支持拖拽区输入文字
基础展示
未加修饰的上传组件,listtype的三种展示形式如下:
图片picture
上传文件后,一个一行,自带边框。
图片卡片picture-card
上传文件后,多个一行,无文件名,需要支持展示。
文字text
上传文件后,一个一行。
根据设计方案实现
上传区域支持插槽
定义了插槽uploadBox
。若没使用插槽uploadBox
,则展示默认内容。
<!-- 上传区域 -->
<template v-if="!$slots.uploadBox">
<i class="el-icon-plus"></i>
<div class="el-upload__text">
<!-- 若有想展示在组件拖拽区的文字,请使用此插槽 -->
<slot name="uploadText" />
</div>
</template>
<!-- 自定义上传区域内容 -->
<slot v-else name="uploadBox" />
补一下上传的小问题,在data
中定义fileList
,给el-upload
上传组件用(data() { fileList: [] }
)。数据并不是双向绑定的,需要在上传成功后,自己推入fileList
中,this.fileList.push(file)
。
// 上传成功,抛出文件给父组件
async handleSuccess (response, file, fileList) {
await afterSuccess(response, file, fileList);
this.$emit("afterUplod", file);
this.fileList.push(file)
},
内容区域支持插槽
定义了插槽uploadContent
。若没有使用插槽uploadContent
,则展示默认内容。
若不想展示文件列表,就使用插槽,但不传内容。
经过试验,直接定义插槽uploadContent
,不行~
el-upload的内容区域,要通过它的插槽去file
去修改~
所以,微微调整一下~
<!-- 内容区域,只对图片卡片picture-card模式,做默认展示 -->
<div
v-if="!$slots.uploadContentBox && ['picture-card'].includes(listType)"
slot="file"
slot-scope="{ file }"
>
<img
class="el-upload-list__item-thumbnail"
:src="handleProcessImgUrl(file)"
alt=""
/>
<el-tooltip :content="file.name">
<span v-if="isShowFileName" class="down-name">
{{ file.name }}</span
>
</el-tooltip>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
v-if="!isDisabled"
class="el-upload-list__item-delete"
@click="handleRemove(file, true)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
<!-- 可自定义内容区域 -->
<div
v-else
slot="file"
slot-scope="{ file }"
>
<slot name="uploadContentBox" :file="file" />
</div>
样式,隐藏上传按钮
:class="[
classNameStr,
{ 'is-hide': fileList.length >= limit || isDisabled },
{ 'pic-wrapper': isShowFileName }
]"
抽离公共方法、变量定义
① 检查文件是否符合要求:格式、大小
② 上传成功后回调
③ 删除方法
④ 获取文件后缀之类的小方法
⑤ 其他方法,巴拉巴拉
抽离的内容放在upload.js
里,简单贴两个方法供参考啦~
// 检查文件格式和文件大小
function checkFileTypeSize(rawFile, accept, maxSizeM ) {
const acceptArr = filterValidArr(accept.split(","))
const suffix = getSuffix(rawFile.name, true);
if (acceptArr.length > 0 && !acceptArr.includes(suffix)) {
tipMsgFun(`请上传需要的文件(${accept})`, 'warning')
return false;
} else if (!!maxSizeM && rawFile.size / 1024 / 1024 > maxSizeM) {
tipMsgFun(`上传文件大小不能超过${maxSizeM}MB`, 'warning')
return false;
}
return true;
}
function removeFile(fileList, file) {
let delIdx = null;
fileList.forEach((item, index) => {
if (item.uid === file.uid) {
delIdx = index;
}
});
fileList.splice(delIdx, 1);
return fileList
}
试了一下贴所有代码,太冗余了,不贴啦~
就酱紫,结束。
转载自:https://juejin.cn/post/7237009597583130681