基于oss与Elment+的图片上传方案

251 阅读1分钟
<template>
    <el-upload
        class="upload-demo"
        :action="host"
        :data="uploadKey"
        :accept="fileType"
        :drag="isDrag"
        :before-upload="beforeUpload"
        :on-change="uploadChange"
        :show-file-list="false"
    >
        <el-button size="small" :type="btnType" @click="getClientKey">
            {{ btnText }}
        </el-button>
    </el-upload>
</template>

<script lang="ts">
import { reactive, toRefs } from 'vue';
import { getThumbnailPolicy } from '@/api/oss';
import { ElMessage } from 'element-plus';

interface State {
    isDrag?: boolean;
    btnType?: string;
    btnText?: string;
    imgUrl: any;
    itemId: string;
    uploadKey: {
        key?: string;
        policy?: string;
        signature?: string;
        OSSAccessKeyId?: string;
        success_action_status?: number;
    };
    host: string;
    dir: string;
}
export default {
    name: 'uploadBox',
    props: {
        drag: {
            type: Boolean,
            default: false
        },
        btnType: {
            type: String,
            default: 'primary'
        },
        btnText: {
            type: String
        },
        fileType:{
            type: String
        }
    },
    emits: ['onFinish'],
    setup(props: any, { emit }: any) {
        const state = reactive<State>({
            isDrag: props.drag,
            btnType: props.btnType,
            btnText: props.btnText,
            itemId: props.itemId,
            imgUrl: '',
            uploadKey: {    // 上传到阿里云所需要的参数
                key: '',
                policy: '',
                signature: '',
                OSSAccessKeyId: '',
                success_action_status: 200
            },
            host: '', // 上传回执的host
            dir: '' // 上传回执的 dir
        });

        /**
            上传之前,点击按钮的时候获取上传参数, 注意,elplus一定要在进行真正的上传之前数,在before-获取到所需的参数,upload,on-change时获取就已经晚了。
        */
        const getClientKey = () => {
            getThumbnailPolicy().then((res: any) => {
                if (res.dir) {
                    state.uploadKey = {
                        policy: res.policy,
                        signature: res.signature,
                        OSSAccessKeyId: res.accessid,
                        success_action_status: 200
                    };
                    state.host = res.host;
                    state.dir = res.dir;
                }
            });
        };

        const beforeUpload = (file: any) => {
            const ext = file.type.split('/')[1];
            const uid = Math.floor(
                new Date().getTime() * Math.random() * Math.random()
            ); // 将file的uid变成更不容易重复的唯一值
            state.uploadKey.key = `media/images/${uid}.${ext}`;
            state.imgUrl = uid;
            if (file.size > 1024 * 1024 * 100) {
                ElMessage.error(`单个文件${file.name}不能大于100M`);
                return false;
            } else if (file.size <= 0) {
                ElMessage.error(`文件${file.name}不能为空`);
                return false;
            }
        };

        /***
         * 上传状态改变函数,如添加文件,文件上传成功,文件上传失败时都会调用该函数
         */
        const uploadChange = (file: any) => {
            if (file.status === 'success') {
                const ext = file.raw.type.split('/')[1]; // 后缀
                let imgUrl = `${state.host}/${state.dir}${state.imgUrl}.${ext}`;
                emit('onFinish', {arg});
            } else if (file.status === 'fail') {
                ElMessage.error('上传失败,请重新上传');
            }
        };

        return {
            ...toRefs(state),
            uploadChange,
            beforeUpload,
            getClientKey
        };
    }
};
</script>