feat: 添加单图上传组件和使用示例

This commit is contained in:
ray
2024-10-10 13:20:32 +08:00
parent 6f0191577f
commit 20c0a89d0d
3 changed files with 214 additions and 7 deletions

View File

@@ -0,0 +1,163 @@
<!-- 单图上传组件 -->
<template>
<el-upload
v-model="imgUrl"
class="img-upload"
:show-file-list="false"
list-type="picture-card"
:before-upload="handleBeforeUpload"
:http-request="uploadFile"
:style="{ width: props.size, height: props.size }"
:accept="props.accept"
>
<template #default>
<el-image v-if="imgUrl" :src="imgUrl" />
<div v-if="imgUrl" class="img-upload__overlay">
<el-icon class="img-upload__preview-icon" @click.stop="handlePreview">
<ZoomIn />
</el-icon>
<el-icon class="img-upload__delete-icon" @click.stop="handleDelete">
<Delete />
</el-icon>
</div>
<el-icon v-else class="img-upload__add-icon">
<Plus />
</el-icon>
</template>
</el-upload>
</template>
<script setup lang="ts">
import {
ElImageViewer,
UploadRawFile,
UploadRequestOptions,
} from "element-plus";
import FileAPI from "@/api/file";
const props = defineProps({
modelValue: {
type: String,
default: "",
},
maxSize: {
type: Number,
default: 10, // 默认限制为 10MB
},
accept: {
type: String,
default: "",
},
size: {
type: String,
default: "150px",
},
});
const emit = defineEmits(["update:modelValue"]);
const imgUrl = defineModel("modelValue", {
type: String,
required: true,
default: "",
});
/**
* 自定义图片上传
*
* @param options
*/
async function uploadFile(options: UploadRequestOptions): Promise<any> {
const data = await FileAPI.upload(options.file);
imgUrl.value = data.url;
}
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
if (file.size > props.maxSize * 1024 * 1024) {
ElMessage.warning(`上传图片不能大于${props.maxSize}MB`);
return false;
}
return true;
}
/**
* 预览图片
*/
function handlePreview() {
if (imgUrl.value) {
const imageViewerApp = createApp({
setup() {
return () =>
h(ElImageViewer, {
urlList: [imgUrl.value],
initialIndex: 0,
onClose: () => {
imageViewerApp.unmount();
document.body.removeChild(container);
},
});
},
});
const container = document.createElement("div");
document.body.appendChild(container);
imageViewerApp.mount(container);
}
}
/**
* 删除图片
*/
function handleDelete() {
imgUrl.value = "";
}
</script>
<style scoped lang="scss">
:deep(.el-upload--picture-card) {
/* width: var(--el-upload-picture-card-size);
height: var(--el-upload-picture-card-size); */
width: 100%;
height: 100%;
}
.img-upload {
position: relative;
overflow: hidden;
cursor: pointer;
border: 1px var(--el-border-color) solid;
border-radius: 5px;
&:hover {
border-color: var(--el-color-primary);
}
&__delete-icon {
margin-left: 5px;
}
&__overlay {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: #fff;
background-color: var(--el-overlay-color-lighter);
border-radius: 6px;
opacity: 0;
transition: opacity var(--el-transition-duration);
&:hover {
opacity: 1;
}
}
}
</style>

View File

@@ -66,13 +66,11 @@ declare module "vue" {
GithubCorner: (typeof import("./../components/GithubCorner/index.vue"))["default"];
Hamburger: (typeof import("./../components/Hamburger/index.vue"))["default"];
IconSelect: (typeof import("./../components/IconSelect/index.vue"))["default"];
LangSelect: (typeof import("./../components/LangSelect/index.vue"))["default"];
MenuSearch: (typeof import("./../components/MenuSearch/index.vue"))["default"];
Notice: (typeof import("./../components/Notice/index.vue"))["default"];
NoticeDetail: (typeof import("../views/system/notice/notice-detail.vue"))["default"];
LayoutSelect: (typeof import("./../layout/components/Settings/components/LayoutSelect.vue"))["default"];
MultiUpload: (typeof import("./../components/Upload/MultiUpload.vue"))["default"];
NavBar: (typeof import("./../layout/components/NavBar/index.vue"))["default"];
NavbarAction: (typeof import("./../layout/components/NavBar/components/NavbarAction.vue"))["default"];
PageContent: (typeof import("./../components/CURD/PageContent.vue"))["default"];
@@ -89,12 +87,14 @@ declare module "vue" {
SidebarMenuItem: (typeof import("./../layout/components/Sidebar/components/SidebarMenuItem.vue"))["default"];
SidebarMenuItemTitle: (typeof import("./../layout/components/Sidebar/components/SidebarMenuItemTitle.vue"))["default"];
SidebarMixTopMenu: (typeof import("./../layout/components/Sidebar/components/SidebarMixTopMenu.vue"))["default"];
SingleUpload: (typeof import("./../components/Upload/SingleUpload.vue"))["default"];
SizeSelect: (typeof import("./../components/SizeSelect/index.vue"))["default"];
SvgIcon: (typeof import("./../components/SvgIcon/index.vue"))["default"];
TableSelect: (typeof import("./../components/TableSelect/index.vue"))["default"];
TagsView: (typeof import("./../layout/components/TagsView/index.vue"))["default"];
ThemeColorPicker: (typeof import("./../layout/components/Settings/components/ThemeColorPicker.vue"))["default"];
FileUpload: (typeof import("./../components/Upload/FileUpload.vue"))["default"];
ImageUpload: (typeof import("./../components/Upload/ImageUpload.vue"))["default"];
SingleImageUpload: (typeof import("./../components/Upload/SingleImageUpload.vue"))["default"];
WangEditor: (typeof import("./../components/WangEditor/index.vue"))["default"];
}
export interface ComponentCustomProperties {

View File

@@ -2,8 +2,38 @@
<script setup lang="ts">
import ImageUpload from "@/components/Upload/ImageUpload.vue";
import FileUpload from "@/components/Upload/FileUpload.vue";
const size = ref("");
// 这里放外链图片,防止被删
// 单图
const picUrl = ref("https://s2.loli.net/2023/05/24/yNsxFC8rLHMZQcK.jpg");
const singleImageUploadArgData = [
{
argsName: "v-model",
type: "String",
default: "",
desc: "已经上传的图片URL",
},
{
argsName: "size",
type: "String",
default: "148px",
desc: "图片上传组件的尺寸大小",
},
{
argsName: "maxSize",
type: "Number",
default: "10",
desc: "单个图片上传大小限制(单位M)",
},
{
argsName: "accept",
type: "String",
default: "",
desc: "上传文件类型",
},
];
// 多图
const picUrls = ref([
"https://s2.loli.net/2023/05/24/yNsxFC8rLHMZQcK.jpg",
"https://s2.loli.net/2023/05/24/RuHFMwW4rG5lIqs.jpg",
@@ -11,10 +41,11 @@ const picUrls = ref([
"https://s2.loli.net/2023/05/24/e1bcnEq3MFdmlNL.jpg",
"https://s2.loli.net/2023/05/24/wZTSPj1yDQNcuhU.jpg",
]);
const imageUploadArgData = [
{
argsName: "v-model",
type: "Arrays",
type: "Array",
default: "[]",
desc: "已经上传的图片数组",
},
@@ -184,7 +215,19 @@ const fileUploadArgData = [
</el-link>
<el-form>
<el-form-item label="图上传">
<el-form-item label="图上传">
<SingleImageUpload v-model="picUrl" />
</el-form-item>
<el-form-item label="参数说明">
<el-table :data="singleImageUploadArgData" border>
<el-table-column prop="argsName" label="参数名称" width="300" />
<el-table-column prop="type" label="参数类型" width="200" />
<el-table-column prop="default" label="默认值" width="400" />
<el-table-column prop="desc" label="描述" width="300" />
</el-table>
</el-form-item>
<el-form-item label="多图上传">
<image-upload v-model="picUrls" />
</el-form-item>
<el-form-item label="参数说明">
@@ -195,6 +238,7 @@ const fileUploadArgData = [
<el-table-column prop="desc" label="描述" width="300" />
</el-table>
</el-form-item>
<el-form-item label="文件上传">
<file-upload v-model="fileUrls" />
</el-form-item>