1. 程式人生 > >【上傳元件優化】el-upload元件結合上傳阿里雲OSS實現更優互動

【上傳元件優化】el-upload元件結合上傳阿里雲OSS實現更優互動

1、效果展示

2、實現程式碼

在components目錄下,新建元件 myImgUpload.vue,程式碼如下:

<template>
    <div>
        <el-upload
            :class="disabled ? 'hideAdd' : 'showAdd'"
            ref="myImgUpload"
            list-type="picture-card"
            :multiple="limit > 1"
            :disabled="disabled"
            :file-list="fileList"
            :accept="accept"
            :limit="limit"
            :on-exceed="onExceed"
            :action="action"
            :data="params"
            :before-upload="beforeUpload"
            :on-success="onSuccess"
            :on-remove="onRemove"
            :on-error="onError"
            :on-preview="onPreview"
            :with-credentials="true">
            <i class="el-icon-plus"></i>
        </el-upload>
        <el-dialog :visible.sync="dialogVisible" append-to-body>
            <img width="100%" :src="dialogImageUrl" alt="">
        </el-dialog>
        <div v-if='tip' class="tip">{{tip}}</div>
    </div>
</template>

<script>
    export default {
        props: {
            action: {
                type: String,
                default: `${window.baseUrl}web/upload/getAvatarUploadInfo`
            },
            value: {
                type: String,
                default: ''
            },
            fileList: null,
            isEdit: {
                type: Boolean,
                default: false
            },
            tip: {
                type: String,
                default: ''
            },
            disabled: {
                type: Boolean,
                default: false
            },
            // 限制上傳數量,預設是1張
            limit: {
                type: Number,
                default: 1
            },
            // 限制上傳大小,預設是5M
            maxsize: {
                type: Number,
                default: 5
            },
            // 限制上傳檔案格式,預設是1 - 圖片
            // 檔案型別:1:圖片(.jpg/.png) ;2:so檔案/txt檔案上傳(.so/.txt);3:provision檔案上傳(.mobileprovision)
            fileType: {
                type: Number,
                default: 1
            }
        },
        data() {
            return {
                params: {
                    'fileType': 1,
                    'fileName': 'default.jpg'
                },
                dialogImageUrl: '',
                dialogVisible: false,
                accept: ''
            }
        },
        created() {
            switch (this.fileType) {
            case 1:
                this.accept = 'image/*'
                break
            default:
                this.accept = '*'
            }
        },
        methods: {
            uploadAliyun(res, file) {
                if (res.code === '000') {
                    let objectName = res.data.key
                    let OSS = require('ali-oss')
                    let client = new OSS({
                        region: res.data.regionId,
                        accessKeyId: res.data.accessKeyId,
                        accessKeySecret: res.data.accessKeySecret,
                        stsToken: res.data.securityToken,
                        bucket: res.data.bucket
                    })
                    const put = async() => {
                        try {
                            let result = await client.put(objectName, file.raw)
                            if (result.res.statusCode === 200) {
                                console.log('上傳阿里雲成功')
                                // this.$message.success('上傳成功')
                            } else {
                                this.$message.error('上傳阿里雲失敗')
                            }
                        } catch (e) {
                            this.$message.error(e)
                        }
                    }
                    put()
                } else {
                    this.$message.error(res.message)
                }
            },
            clearFiles () {
                this.$refs.myImgUpload.clearFiles()
            },
            beforeUpload(file) {
                this.params.fileName = file.name
                const isJPG = file.type === 'image/jpeg'
                const isPNG = file.type === 'image/png'
                const isRightSize = file.size / 1024 / 1024 < this.maxsize
                if (!isJPG && !isPNG) {
                    this.$message.error('上傳頭像圖片只能是 JPG 或 PNG 格式!')
                }
                if (!isRightSize) {
                    this.$message.error('上傳圖片大小不能超過最大限制!')
                }
                return (isJPG || isPNG) && isRightSize
            },
            onSuccess(res, file, fileList) {
                this.$message.success('上傳成功')
                let val = ''
                fileList.forEach(item => {
                    if (val !== '') {
                        val += ','
                    }
                    if (item.response) {
                        val += item.response.data.downloadPath
                    } else {
                        val += item.url
                    }
                })
                this.$emit('input', val)
                this.uploadAliyun(res, file)
            },
            onPreview(file) {
                this.dialogImageUrl = file.url
                this.dialogVisible = true
            },
            onExceed(files, fileList) {
                this.$message({
                    message: '上傳數量超出最大限制!',
                    type: 'warning'
                })
            },
            onRemove(res, fileList) {
                let val = ''
                fileList.forEach(item => {
                    if (val !== '') {
                        val += ','
                    }
                    if (item.response) {
                        val += item.response.data.downloadPath
                    } else {
                        val += item.url
                    }
                })
                this.$emit('input', val)
            },
            onError(err) {
                console.log('this is onError:\n', err)
            }
        }
    }
</script>

<style lang='less' scope>
    .tip {
        color: #606266;
        font-size: 12px;
    }
    .hideAdd {
        .el-upload--picture-card {
            display: none;
        }
    }
    .showAdd {
        .el-upload--picture-card {
            display: block;
        }
    }
</style>

3、設計思路:

在之前的一篇文章中(【上傳檔案】基於阿里雲的視訊點播VOD、物件儲存OSS實現音視訊圖片等檔案上傳),我們用了一個簡單的 el-button 結合原生 input 來實現了上傳檔案至阿里雲,但是互動上存在諸多漏洞,比方說我上傳了一張圖片之後只能替換無法刪除;上傳成功之後無法預覽圖片等等。所以,這次我們基於 el-upload 來更好地去實現這個上傳功能,互動上也表現地更合理些。

實現的關鍵在於對 el-upload上傳生命週期 的理解,在合適的時間上做合適的事情!比如:在合適的時間(beforeUpload)對檔案格式做校驗,在合適的時間(onSuccess)上傳檔案至阿里雲OSS,在合適的時間(onSuccess/onRemove

)與父元件通訊(this.$emit('input', val))。