-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
cloud-mouse
committed
Sep 23, 2024
1 parent
877814f
commit 8865c42
Showing
11 changed files
with
833 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<template> | ||
<ElUpload | ||
:headers="headers" | ||
:action="action" | ||
:data="data" | ||
:name="name" | ||
:before-upload="beforeUpload" | ||
:on-exceed="onExceed" | ||
:on-success="onSuccess" | ||
:file-list="files" | ||
:limit="max" | ||
drag | ||
> | ||
<div class="slot"> | ||
<SvgIcon name="ep:upload-filled" class="el-icon--upload" /> | ||
<div class="el-upload__text"> | ||
将文件拖到此处,或<em>点击上传</em> | ||
</div> | ||
</div> | ||
<template #tip> | ||
<div v-if="!notip" class="el-upload__tip"> | ||
<div style="display: inline-block;"> | ||
<ElAlert :title="`上传文件支持 ${ext.join(' / ')} 格式,单个文件大小不超过 ${size}MB,且文件数量不超过 ${max} 个`" type="info" show-icon :closable="false" /> | ||
</div> | ||
</div> | ||
</template> | ||
</ElUpload> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import type { UploadProps, UploadUserFile } from 'element-plus' | ||
import { ElMessage } from 'element-plus' | ||
defineOptions({ | ||
name: 'FileUpload', | ||
}) | ||
const props = withDefaults( | ||
defineProps<{ | ||
action: UploadProps['action'] | ||
headers?: UploadProps['headers'] | ||
data?: UploadProps['data'] | ||
name?: UploadProps['name'] | ||
size?: number | ||
max?: number | ||
files?: UploadUserFile[] | ||
notip?: boolean | ||
ext?: string[] | ||
}>(), | ||
{ | ||
name: 'file', | ||
size: 2, | ||
max: 3, | ||
files: () => [], | ||
notip: false, | ||
ext: () => ['zip', 'rar'], | ||
}, | ||
) | ||
const emits = defineEmits<{ | ||
onSuccess: [ | ||
res: any, | ||
file: UploadUserFile, | ||
fileList: UploadUserFile[], | ||
] | ||
}>() | ||
const beforeUpload: UploadProps['beforeUpload'] = (file) => { | ||
const fileName = file.name.split('.') | ||
const fileExt = fileName.at(-1) ?? '' | ||
const isTypeOk = props.ext.includes(fileExt) | ||
const isSizeOk = file.size / 1024 / 1024 < props.size | ||
if (!isTypeOk) { | ||
ElMessage.error(`上传文件只支持 ${props.ext.join(' / ')} 格式!`) | ||
} | ||
if (!isSizeOk) { | ||
ElMessage.error(`上传文件大小不能超过 ${props.size}MB!`) | ||
} | ||
return isTypeOk && isSizeOk | ||
} | ||
const onExceed: UploadProps['onExceed'] = () => { | ||
ElMessage.warning('文件上传超过限制') | ||
} | ||
const onSuccess: UploadProps['onSuccess'] = (res, file, fileList) => { | ||
emits('onSuccess', res, file, fileList) | ||
} | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
:deep(.el-upload.is-drag) { | ||
display: inline-block; | ||
.el-upload-dragger { | ||
padding: 0; | ||
} | ||
&.is-dragover { | ||
border-width: 1px; | ||
} | ||
.slot { | ||
width: 300px; | ||
padding: 40px 0; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
<template> | ||
<div class="upload-container"> | ||
<ElUpload | ||
:show-file-list="false" | ||
:headers="headers" | ||
:action="action" | ||
:data="data" | ||
:name="name" | ||
:before-upload="beforeUpload" | ||
:on-progress="onProgress" | ||
:on-success="onSuccess" | ||
drag | ||
class="image-upload" | ||
> | ||
<ElImage v-if="url === ''" :src="url === '' ? placeholder : url" :style="`width:${width}px;height:${height}px;`" fit="fill"> | ||
<template #error> | ||
<div class="image-slot" :style="`width:${width}px;height:${height}px;`"> | ||
<SvgIcon name="ep:plus" class="icon" /> | ||
</div> | ||
</template> | ||
</ElImage> | ||
<div v-else class="image"> | ||
<ElImage :src="url" :style="`width:${width}px;height:${height}px;`" fit="fill" /> | ||
<div class="mask"> | ||
<div class="actions"> | ||
<span title="预览" @click.stop="preview"> | ||
<SvgIcon name="ep:zoom-in" class="icon" /> | ||
</span> | ||
<span title="移除" @click.stop="remove"> | ||
<SvgIcon name="ep:delete" class="icon" /> | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
<div v-show="url === '' && uploadData.progress.percent" class="progress" :style="`width:${width}px;height:${height}px;`"> | ||
<ElImage :src="uploadData.progress.preview" :style="`width:${width}px;height:${height}px;`" fit="fill" /> | ||
<ElProgress type="circle" :width="Math.min(width, height) * 0.8" :percentage="uploadData.progress.percent" /> | ||
</div> | ||
</ElUpload> | ||
<div v-if="!notip" class="el-upload__tip"> | ||
<div style="display: inline-block;"> | ||
<ElAlert :title="`上传图片支持 ${ext.join(' / ')} 格式,且图片大小不超过 ${size}MB,建议图片尺寸为 ${width}*${height}`" type="info" show-icon :closable="false" /> | ||
</div> | ||
</div> | ||
<ElImageViewer v-if="uploadData.imageViewerVisible" :url-list="[url]" teleported @close="previewClose" /> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import type { UploadProps } from 'element-plus' | ||
import { ElMessage } from 'element-plus' | ||
defineOptions({ | ||
name: 'ImageUpload', | ||
}) | ||
const props = withDefaults( | ||
defineProps<ImageUploadProps>(), | ||
{ | ||
name: 'file', | ||
size: 2, | ||
width: 150, | ||
height: 150, | ||
placeholder: '', | ||
notip: false, | ||
ext: () => ['jpg', 'png', 'gif', 'bmp'], | ||
}, | ||
) | ||
const emits = defineEmits<{ | ||
onSuccess: [ | ||
res: any, | ||
] | ||
}>() | ||
interface ImageUploadProps { | ||
action: UploadProps['action'] | ||
headers?: UploadProps['headers'] | ||
data?: UploadProps['data'] | ||
name?: UploadProps['name'] | ||
size?: number | ||
width?: number | ||
height?: number | ||
placeholder?: string | ||
notip?: boolean | ||
ext?: string[] | ||
} | ||
const url = defineModel<string>({ | ||
default: '', | ||
}) | ||
const uploadData = ref({ | ||
imageViewerVisible: false, | ||
progress: { | ||
preview: '', | ||
percent: 0, | ||
}, | ||
}) | ||
// 预览 | ||
function preview() { | ||
uploadData.value.imageViewerVisible = true | ||
} | ||
// 关闭预览 | ||
function previewClose() { | ||
uploadData.value.imageViewerVisible = false | ||
} | ||
// 移除 | ||
function remove() { | ||
url.value = '' | ||
} | ||
const beforeUpload: UploadProps['beforeUpload'] = (file) => { | ||
const fileName = file.name.split('.') | ||
const fileExt = fileName.at(-1) ?? '' | ||
const isTypeOk = props.ext.includes(fileExt) | ||
const isSizeOk = file.size / 1024 / 1024 < props.size | ||
if (!isTypeOk) { | ||
ElMessage.error(`上传图片只支持 ${props.ext.join(' / ')} 格式!`) | ||
} | ||
if (!isSizeOk) { | ||
ElMessage.error(`上传图片大小不能超过 ${props.size}MB!`) | ||
} | ||
if (isTypeOk && isSizeOk) { | ||
uploadData.value.progress.preview = URL.createObjectURL(file) | ||
} | ||
return isTypeOk && isSizeOk | ||
} | ||
const onProgress: UploadProps['onProgress'] = (file) => { | ||
uploadData.value.progress.percent = ~~file.percent | ||
} | ||
const onSuccess: UploadProps['onSuccess'] = (res) => { | ||
uploadData.value.progress.preview = '' | ||
uploadData.value.progress.percent = 0 | ||
emits('onSuccess', res) | ||
} | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
.upload-container { | ||
line-height: initial; | ||
} | ||
.el-image { | ||
display: block; | ||
} | ||
.image { | ||
position: relative; | ||
overflow: hidden; | ||
border-radius: 6px; | ||
.mask { | ||
position: absolute; | ||
top: 0; | ||
width: 100%; | ||
height: 100%; | ||
background-color: var(--el-overlay-color-lighter); | ||
opacity: 0; | ||
transition: opacity 0.3s; | ||
.actions { | ||
display: flex; | ||
flex-wrap: wrap; | ||
align-items: center; | ||
justify-content: center; | ||
width: 100px; | ||
height: 100px; | ||
@include position-center(xy); | ||
span { | ||
width: 50%; | ||
color: var(--el-color-white); | ||
text-align: center; | ||
cursor: pointer; | ||
transition: color 0.1s, transform 0.1s; | ||
&:hover { | ||
transform: scale(1.5); | ||
} | ||
.icon { | ||
font-size: 24px; | ||
} | ||
} | ||
} | ||
} | ||
&:hover .mask { | ||
opacity: 1; | ||
} | ||
} | ||
.image-upload { | ||
display: inline-block; | ||
vertical-align: top; | ||
} | ||
:deep(.el-upload) { | ||
.el-upload-dragger { | ||
display: inline-block; | ||
padding: 0; | ||
&.is-dragover { | ||
border-width: 1px; | ||
} | ||
.image-slot { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
width: 100%; | ||
height: 100%; | ||
color: var(--el-text-color-placeholder); | ||
background-color: transparent; | ||
.icon { | ||
font-size: 30px; | ||
} | ||
} | ||
.progress { | ||
position: absolute; | ||
top: 0; | ||
&::after { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
content: ""; | ||
background-color: var(--el-overlay-color-lighter); | ||
} | ||
.el-progress { | ||
z-index: 1; | ||
@include position-center(xy); | ||
.el-progress__text { | ||
color: var(--el-text-color-placeholder); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
</style> |
Oops, something went wrong.