优化上传组件

This commit is contained in:
icssoa 2023-05-30 21:51:38 +08:00
parent 6f7b8dc213
commit 6dde8feb32
3 changed files with 121 additions and 64 deletions

View File

@ -13,8 +13,12 @@
<cl-upload v-model="v3" multiple text="文件上传" type="file" /> <cl-upload v-model="v3" multiple text="文件上传" type="file" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="可拖拽"> <el-tab-pane label="拖拽">
<el-divider content-position="left"> 拖拽排序 </el-divider>
<cl-upload multiple draggable /> <cl-upload multiple draggable />
<el-divider content-position="left"> 拖拽上传 </el-divider>
<cl-upload drag :size="[160, 300]" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="自定义内容"> <el-tab-pane label="自定义内容">
@ -27,10 +31,6 @@
</cl-upload> </cl-upload>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="自定义大小">
<cl-upload :size="[120, 200]" />
</el-tab-pane>
<el-tab-pane label="上传校验"> <el-tab-pane label="上传校验">
<cl-upload :before-upload="onBeforeUpload" /> <cl-upload :before-upload="onBeforeUpload" />
</el-tab-pane> </el-tab-pane>
@ -55,7 +55,7 @@
<script lang="ts" name="demo-upload" setup> <script lang="ts" name="demo-upload" setup>
import { ref } from "vue"; import { ref } from "vue";
import { Upload } from "@element-plus/icons-vue"; import { Upload, UploadFilled } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const v1 = ref(""); const v1 = ref("");

View File

@ -5,34 +5,45 @@
:class="[ :class="[
`cl-upload--${type}`, `cl-upload--${type}`,
{ {
'is-disabled': disabled 'is-disabled': disabled,
'is-drag': drag
} }
]" ]"
> >
<div class="cl-upload__file-btn" v-if="type == 'file'" @click="space.open()"> <template v-if="!drag">
<el-upload <div class="cl-upload__file-btn" v-if="type == 'file'" @click="space.open()">
:ref="setRefs('upload')" <el-upload
action="" :ref="setRefs('upload')"
:accept="accept" :drag="drag"
:show-file-list="false" action=""
:before-upload="beforeUpload" :accept="accept"
:http-request="httpRequest" :show-file-list="false"
:headers="headers" :before-upload="beforeUpload"
:multiple="multiple" :http-request="httpRequest"
:disabled="uploadDisabled" :headers="headers"
> :multiple="multiple"
<slot> :disabled="uploadDisabled"
<el-button type="success">{{ text }}</el-button> >
</slot> <slot>
</el-upload> <el-button type="success">{{ text }}</el-button>
</div> </slot>
</el-upload>
</div>
</template>
<!-- 列表 --> <!-- 列表 -->
<draggable <draggable
class="cl-upload__list" class="cl-upload__list"
tag="div" tag="div"
v-model="list" v-model="list"
v-bind="drag.options" :options="{
group: 'Upload',
animation: 300,
ghostClass: 'Ghost',
dragClass: 'Drag',
draggable: '.is-drag',
disabled: !draggable
}"
item-key="uid" item-key="uid"
@end="update" @end="update"
v-if="showFileList" v-if="showFileList"
@ -40,10 +51,11 @@
<template #footer> <template #footer>
<div <div
class="cl-upload__footer" class="cl-upload__footer"
v-if="type == 'image' && isAdd" v-if="(type == 'image' || drag) && isAdd"
@click="space.open()" @click="space.open()"
> >
<el-upload <el-upload
:drag="drag"
:ref="setRefs('upload')" :ref="setRefs('upload')"
action="" action=""
:accept="accept" :accept="accept"
@ -55,8 +67,18 @@
:disabled="uploadDisabled" :disabled="uploadDisabled"
> >
<slot> <slot>
<div class="cl-upload__item"> <div class="cl-upload__dragger" v-if="drag">
<el-icon :size="24"><picture-filled /></el-icon> <el-icon><upload-filled /></el-icon>
<div>
点击上传或将文件拖动到此处文件大小限制{{ limitSize }}M
</div>
</div>
<div class="cl-upload__item" v-else>
<el-icon :size="24">
<component :is="icon" v-if="icon" />
<picture-filled v-else />
</el-icon>
<span class="cl-upload__text" v-if="text">{{ text }}</span> <span class="cl-upload__text" v-if="text">{{ text }}</span>
</div> </div>
</slot> </slot>
@ -98,17 +120,12 @@
<span class="cl-upload__name"> <span class="cl-upload__name">
{{ fileName(item.preload) }}.{{ extname(item.preload) }} {{ fileName(item.preload) }}.{{ extname(item.preload) }}
</span> </span>
<!-- 大小 -->
<span class="cl-upload__size">
{{ fileSize(item.size) }}
</span>
</template> </template>
<!-- 工具 --> <!-- 工具 -->
<div class="cl-upload__actions"> <div class="cl-upload__actions">
<!-- 预览 --> <!-- 预览 -->
<el-icon @click.stop="preview(item)" v-show="item.url"> <el-icon @click.stop="preview(item)">
<zoom-in /> <zoom-in />
</el-icon> </el-icon>
@ -152,15 +169,15 @@
</template> </template>
<script lang="ts" setup name="cl-upload"> <script lang="ts" setup name="cl-upload">
import { computed, ref, reactive, watch, PropType } from "vue"; import { computed, ref, watch, PropType } from "vue";
import { isArray, isNumber } from "lodash-es"; import { isArray, isNumber } from "lodash-es";
import Draggable from "vuedraggable"; import Draggable from "vuedraggable";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { PictureFilled, ZoomIn, Delete } from "@element-plus/icons-vue"; import { PictureFilled, ZoomIn, Delete, UploadFilled } from "@element-plus/icons-vue";
import { useCool, module } from "/@/cool"; import { useCool, module } from "/@/cool";
import { extname, uuid, isPromise } from "/@/cool/utils"; import { extname, uuid, isPromise } from "/@/cool/utils";
import { useBase } from "/$/base"; import { useBase } from "/$/base";
import { fileSize, fileName, fileType, getUrls } from "../utils"; import { fileName, fileType, getUrls } from "../utils";
import { Upload } from "../types"; import { Upload } from "../types";
import ItemViewer from "./items/viewer.vue"; import ItemViewer from "./items/viewer.vue";
@ -182,6 +199,7 @@ const props = defineProps({
default: true default: true
}, },
size: [String, Number, Array], size: [String, Number, Array],
icon: null,
text: String, text: String,
prefixPath: { prefixPath: {
type: String, type: String,
@ -196,6 +214,7 @@ const props = defineProps({
default: true default: true
}, },
draggable: Boolean, draggable: Boolean,
drag: Boolean,
disabled: Boolean, disabled: Boolean,
customClass: String, customClass: String,
beforeUpload: Function, beforeUpload: Function,
@ -250,21 +269,9 @@ const headers = computed(() => {
// //
const list = ref<Upload.Item[]>([]); const list = ref<Upload.Item[]>([]);
//
const drag = reactive({
options: {
group: "Upload",
animation: 300,
ghostClass: "Ghost",
dragClass: "Drag",
draggable: ".is-drag",
disabled: !props.draggable
}
});
// //
const accept = computed(() => { const accept = computed(() => {
return props.accept || (props.type == "file" ? "*" : "image/*"); return props.accept || (props.type == "file" ? "" : "image/*");
}); });
// //
@ -299,6 +306,11 @@ async function beforeUpload(file: any, item?: Upload.Item) {
d.preload = d.preload =
d.url || (d.type == "image" ? window.webkitURL.createObjectURL(file) : file.name); d.url || (d.type == "image" ? window.webkitURL.createObjectURL(file) : file.name);
//
if (!d.url) {
d.url = d.preload;
}
// //
if (item) { if (item) {
Object.assign(item, d); Object.assign(item, d);
@ -319,7 +331,7 @@ async function beforeUpload(file: any, item?: Upload.Item) {
// //
if (props.beforeUpload) { if (props.beforeUpload) {
const r = props.beforeUpload(file, item); const r = props.beforeUpload(file, item, { next });
if (isPromise(r)) { if (isPromise(r)) {
r.then(next).catch(() => null); r.then(next).catch(() => null);
@ -580,6 +592,29 @@ defineExpose({
}); });
</script> </script>
<style lang="scss">
.cl-upload__dragger {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px dashed var(--el-border-color);
padding: 20px;
border-radius: 8px;
font-size: 14px;
color: #666;
height: v-bind("size[0]");
width: v-bind("size[1]");
box-sizing: border-box;
.el-icon {
font-size: 46px;
margin-bottom: 10px;
color: #a8abb2;
}
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.cl-upload { .cl-upload {
line-height: normal; line-height: normal;
@ -687,15 +722,6 @@ defineExpose({
text-align: center; text-align: center;
word-break: break-all; word-break: break-all;
} }
&__size {
position: absolute;
top: 5px;
right: 5px;
font-size: 12px;
line-height: 12px;
color: #999;
}
} }
} }
} }
@ -716,9 +742,32 @@ defineExpose({
box-sizing: border-box; box-sizing: border-box;
} }
&--file { :deep(.el-upload) {
.cl-upload__list { &.is-drag {
margin-top: 10px; .el-upload-dragger {
padding: 0;
border: 0;
background-color: transparent !important;
position: relative;
$color: var(--el-color-primary);
&.is-dragover {
&::after {
display: block;
content: "";
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
pointer-events: none;
border-radius: 8px;
box-sizing: border-box;
border: 1px dashed var(--color-primary);
}
}
}
} }
} }
@ -728,5 +777,13 @@ defineExpose({
background-color: var(--el-disabled-bg-color); background-color: var(--el-disabled-bg-color);
} }
} }
&--file {
&:not(.is-drag) {
.cl-upload__list {
margin-top: 10px;
}
}
}
} }
</style> </style>

View File

@ -10,7 +10,7 @@ export default () => {
// 尺寸 // 尺寸
size: 120, size: 120,
// 显示文案 // 显示文案
text: "选择文件", text: "选择图片",
// 限制 // 限制
limit: { limit: {
// 上传最大数量 // 上传最大数量