element-plus图片上传封装

578 阅读1分钟

<template>
    <!--  -->
   <div :class="uploadDisabled ? 'upload' : ''">
        <el-upload action="#"
            accept=".jpg,.jpeg,.png,.bmp"
            list-type="picture-card"
            :auto-upload="false"
            v-model:file-list="fileList"
            :limit="maxlimit"
            :before-upload="beforeAvatarUpload"
            :on-change="handleChange"
            :on-preview="handlePictureCardPreview"
            :on-remove="handleRemove">
            <el-icon><Plus /></el-icon>
        </el-upload>
        <el-dialog v-model="viewImages">
                <img w-full :src="dialogImageUrl" alt="Preview Image"
                style="width: 950px;height: 460px;"/>
        </el-dialog>
   </div>
</template>

<script lang="ts">
import {
    defineComponent,
    ref,
    watch,
    watchEffect,
} from 'vue';
import axios from 'axios';

import type { AxiosResponse } from 'axios';
import {
    UploadUserFile,
    ElLoading,
    UploadProps,
    UploadFile,
    ElMessage,
} from 'element-plus';

interface Files {
            name: string,
            url: string,
}
interface UploadRawFile extends File {
    uid: number;
}
interface UploadFils {
    name: string;
    percentage?: number;
    size?: number;
    response?: unknown;
    uid: number;
    url?: string;
    raw?: UploadRawFile;
}

export default defineComponent({
    props: {
        updateFile: { // 更新传过来的图片数组
            type: Array,
            default: () => [],
        },
        maxlimit: { // 图片的数量
            type: Number,
            default: 1,
        },
        uploadTypes: { // 文件上传的名称或类型 根据APi 定
            type: String,
            default: 'preview',
        },
        BaseUrl: { // 文件上传地址
            type: String,
            default: import.meta.env.VITE_UPLOAD_URL, // 默认公有上传
        },
        echoAddress: {
            type: String,
            default: '',
        },
        Width: { // 宽度
            type: String,
            default: '148px',
        },
        Hieght: { // 高度
            type: String,
            default: '148px',
        },
    },
    setup(props, context) {
        const fileList = ref<UploadUserFile[]>([]);
        const viewImages = ref(false);
        const dialogImageUrl = ref<string |undefined >('');
        const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
            fileList.value = uploadFiles;
            // 删除图片后重新把数据传出去
            context.emit('removeAfterFile', uploadFiles);
        };
        const handlePictureCardPreview = (file: UploadFile) => {
            dialogImageUrl.value = file.url;
            viewImages.value = true;
        };
        const Width = ref('');
        const Hieght = ref('');
        watch(() => props, (newVal) => {
            fileList.value = newVal.updateFile as Files[];
            Width.value = newVal.Width;
            Hieght.value = newVal.Hieght;
        }, {
            immediate: true,
            deep: true,
        });
        const uploadDisabled = ref(false);
        watchEffect(() => {
            fileList.value = fileList.value.filter((item) => (!item.raw ? item : ''));
            if (fileList.value.length >= props.maxlimit) {
                uploadDisabled.value = true;
            } else {
                uploadDisabled.value = false;
            }
        });
        // 限制尺寸大小
        // var reader = new FileReader();
        // reader.onload = function (event) {
        //     var txt = event.target.result;
        //     var img = document.createElement("img");
        //     img.src = txt;
        //     img.onload = function () {
        //         if (img.width>196 || img.height>110) {
        //             ElMessage.error('图片尺寸最大为196*110')
        //             return reject(false);
        //         }
        //     }
        // };
        // reader.readAsDataURL(rawFile);
        const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
            if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpg' && rawFile.type !== 'image/jpeg') {
                ElMessage.error('图片仅支持jpg、jpeg、png格式!');
                return false;
            } if (rawFile.size / 1024 / 1024 > 3) {
                ElMessage.error('图片大小不能超过3M!');
                return false;
            }
            return true;
        };
        // 图片改变
        const handleChange: UploadProps['onChange'] = async (uploadFile: UploadFils) => {
            const files = new FormData();
            if (uploadFile && uploadFile.raw) {
                files.append(props.uploadTypes, uploadFile.raw);
            }
            const loading = ElLoading.service({
                lock: true,
                text: 'Loading',
                background: 'rgba(0, 0, 0, 0.7)',
            });
            axios({
                // 请求方式 get post delete put
                method: 'post',
                // 请求地址
                url: `${props.BaseUrl}?type=${props.uploadTypes}`,
                // body参数
                data: files,
            }).then((res: AxiosResponse) => {
                if (props.echoAddress === 'false') {
                    context.emit('images', res.data.data);
                    loading.close();
                    return;
                }
                fileList.value.push({
                    name: res.data.data.path,
                    url: res.data.data.url_path,
                });
                // 这是事件传递的父组件接收的图片
                context.emit('images', res.data.data);
                loading.close();
            });
        };
        return {
            fileList,
            viewImages,
            dialogImageUrl,
            uploadDisabled,
            beforeAvatarUpload,
            handleRemove,
            handlePictureCardPreview,
            handleChange,
        };
    },
});
</script>

<style lang="scss" scoped>
.preview_box{
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgb(215, 215, 215);
}
:deep(.el-dialog){
        width: 1000px;
        height: 500px;
    }
:deep(.el-dialog__body){
        padding: 0px 20px;
    }
.upload :deep(.el-upload--picture-card) {
        display: none !important;
}
:deep(.el-upload--picture-card){
    width: v-bind(Width) !important;
    height: v-bind(Hieght) !important;
}
:deep(.el-upload-list__item){
    width: v-bind(Width) !important;
    height: v-bind(Hieght) !important;
}
</style>