elment-ui upload 自定义上传ali-oss视频或

2023-07-22  本文已影响0人  Peter_2B
<template>
    <div>
        <el-upload
            ref="upload"
            action
            accept="video/*, image/*"
            list-type="picture-card"
            :before-upload="beforeUpload"
            :http-request="handleUploadRequest"
            :on-remove="handleRemove"
            :on-exceed="handleExceed"
            :on-preview="handlePreview"
            :show-file-list="true"
            :limit="limit"
            :multiple="true"
            :file-list="fileList"
        >
            <i class="el-icon-plus"></i>
        </el-upload>

        <!-- 视频播放弹框 -->
        <el-dialog :visible.sync="showVideo" width="1000px" append-to-body>
            <video
                v-if="showVideo"
                ref="video"
                :src="videoSrc"
                controls="controls"
                width="100%"
                height="500"
            ></video>
        </el-dialog>

        <!-- 图片预览器 -->
        <el-image-viewer
            v-if="showViewer"
            :on-close="handleCloseViewer"
            :url-list="viewList"
            :z-index="3000"
        />
    </div>
</template>
<script>
import client from "@/utils/ali-oss.js";
import ElImageViewer from "element-ui/packages/image/src/image-viewer";
// 上传视频,截取视频第一帧作为图片的文档:https://help.aliyun.com/document_detail/64555.html?spm=a2c4g.11186623.6.769.283a776bEOUKzW

export default {
    name: "UploadImgAndVideo",
    components: { ElImageViewer },
    props: {
        // 上传文件列表
        fileList: {
            type: Array,
            default: () => {
                return [];
            },
        },
        imgSize: {
            type: [String, Number],
            default: 5,
        },
        videoSize: {
            type: [String, Number],
            default: 50,
        },
    },
    data() {
        return {
            showViewer: false, // 展示图片浏览器
            showVideo: false, // 展示视频播放器
            videoSrc: null, // 视频播放路径
            viewList: [], // 图片浏览列表
            uploadType: null, // 动态限制上传类型;要么只能图片 or 视频
            limit: 9,
        };
    },
    methods: {
        // 上传前
        beforeUpload(file) {
            // 因为此业务需要的是img & video两种类型,上传第一个文件时需要设置后续上传类型
            // 不能在beforeUpload通过fileList[0]判断之前上传的类型,fileList是异步添加,此处的fileList还没添加上;
            let { type, size } = file;
            const M = size / 1024 / 1024;

            if (![/^image/, /^video/].some((it) => it.test(type))) {
                this.$message.warning("请上传视频或图片!");
                return Promise.reject();
            }

            // 图片文件
            if (/^image/.test(type)) {
                this.limit = 9;
                if (M > this.imgSize) {
                    this.$message.warning(`图片大小限制在${this.imgSize}M`);
                    return Promise.reject();
                }

                // 上传第1个文件时,设置后续文件相同类型
                if (this.uploadType === null) {
                    this.uploadType = "image";
                }
            }

            // 视频文件
            if (/^video/.test(type)) {

                if (M > this.videoSize) {
                    this.$message.warning(`视频大小限制在${this.videoSize}M`);
                    return Promise.reject();
                }

                // 这里只能限制第1次上传的数量,无法限制第一次选择了多个视频数量;
                this.limit = 1; 

                // 所以这里需要再判断一下,已上传过一个视频;
                if (this.uploadType !== null) {
                        this.$message.warning("只能上传1个视频!");
                    return Promise.reject();
                } else {
                    // 还未上传过则设置后续上传类型;
                    this.uploadType === "video";
                }
            }
        },
        // 自定义上传方式
        async handleUploadRequest(file) {
            try {
                let pathName =
                    new Date().getTime() +
                    "_" +
                    Math.floor(Math.random() * 1000000) +
                    "_" +
                    file.file.name;

                let res = await client.put(pathName, file.file);
                let temp = {
                    url: res.url,
                    pathName: pathName,
                    fileName: file.file.name,
                    type: file.file.type,
                    uid: file.file.uid,
                };

                if (/^video/.test(file.file.type)) {
                    let picturePath =
                        res.url +
                        "?x-oss-process=video/snapshot,t_1,f_jpg,w_0,h_0,m_fast";
                    // 这里的url是视频封面作为list-file列表小框的图片预览地址;videoUrl视频获取资源的地址;
                    temp.url = picturePath;
                    temp.videoUrl = res.url;
                }

                // 需要返回给后端上传成功后的ali-oss文件url地址;如普通上传可在on-change中接收成功的fileList;
                this.$emit("change", [...this.fileList, temp]);
            } catch (err) {
                console.log(
                    `%c上传ali-oss文件失败 ${err}`,
                    "background: orange"
                );
                // 自定义上传失败不会触发on-error回调函数,采用abort方法终止文件在fileList列表小框中预览回显;
                this.$refs.upload.abort();
            }
        },
        // 删除上传图片; file当前删除文件,fileList删除后剩余的文件列表;
        async handleRemove(file, fileList) {
            try {
                let currentFile = this.fileList.find(
                    (it) => it.uid === file.uid
                );

                // 剩余文件长度为0时,重置上传类型;
                if (fileList.length === 0) {
                    this.uploadType = null;
                }

                // 本地先重置再删远程,避免远程删不成功阻塞,导致本地文件依然占据fileList文件列表中;
                this.$emit("change", fileList);

                // 远程没删成功和本地删除是两回事;
                await client.delete(currentFile.pathName);
            } catch (err) {
                console.log(
                    `%c删除ali-oss远程文件失败 ${err}`,
                    "background: orange"
                );
            }
        },
        // 撤销操作 - 删除ali-oss服务器中上传的文件;
        handleFileListLeft(fileList) {
            return new Promise(async (resolve, reject) => {
                try {
                    for (var i = 0; i < fileList.length; i++) {
                        var file = fileList[i];
                        await client.delete(file.pathName);
                    }
                    resolve();
                } catch (err) {
                    reject(err);
                }
            });
        },
        // 限制上传多少个文件
        handleExceed() {
            this.$message.warning(`只能上传1个视频或9张图片!`);
        },
        // 点击预览
        handlePreview(file) {
            if (/^image/.test(file.type)) {
                this.showViewer = true;
                this.viewList = [file.url];
            } else {
                this.videoSrc = file.videoUrl;
                this.showVideo = true;
            }
        },
        // 图片预览关闭
        handleCloseViewer() {
            this.showViewer = false;
        },
    },
};
</script>

<style scoped lang="less">
.el-dialog {
    .el-dialog__body {
        height: 400px;
    }
}
</style>
上一篇 下一篇

猜你喜欢

热点阅读