el-upload 的那些坑

最近开发项目时,使用 element-plus 所遇到了一些坑,官方对于这块地方并没有很好的阐述,因此我这边自己总结了一下所遇到的问题。

1. 写在 el-upload 里面的任何按钮 都可以触发上传文件窗口 

解决方案:

在你所需要的dom上,写一个防止冒泡的语句 ,比如我写的就是 @clickstop=""  这样就不会触发上传文件的窗口操作了

2. 绑定 fileList 后,为什么 remove 操作不会跟着改变 fileList 的值

这里其实 fileList 只是为了便于我们使用,给到的一个对象,文件列表,只有第一次渲染的是跟fileList 是对应的,后续的 remove 上传操作 ,都需要 我们根据 uploadFiles 自己维护这个 fileList 的值

这里再阐述一下,文档里面标注的 uploadFile  和 uploadFiles 分别代表的是,当前操作的 文件对象 和 此时真正的 上传文件列表(里面包含了文件的字节信息等) 而不是 fileList

另外:upLoadFile 里面的 raw 才是真正的文件内容,自定义上传的传这个属性就行了

3. 多选上传后,触发多次 onchange 事件 

这个会导致什么问题呢,我在写项目的时候,想着说 上传会触发 onchange 事件,是不是每次维护 fileList 的最后一个元素就行了,不是的,虽然会触发多次,第一个回调参数的 uploadFile 是对应一个个多选的文件,但是 uploadFiles 每次都是一样的

因此,我们根据对应的 name 去维护 fileList 的值就行了(在客户端名字是不会重复的)

4. 上传视频的时候,视频是没有缩略图的

为什么指定了,fileList 的 url 视频还是没有缩略图,因为上传列表 对应的是 uploadFiles 的内容。

因此我们需要 对应 修改 uploadFiles 的 url 就能给 视频加缩略图,自定义上传的时候,那么我们如果拿到 uploadFiles ,就能实现这个,只需要我们在 on-change 事件 和 remove 事件,都对 uploadFiles 进行引用,然后修改就行(因为复杂对象是 值传递,会对应修改 uploadFiles 的内容)

代码示例:

使用 tempUloadFiles 记录 每次的 uploadFiles , 这里的 generateVideo 函数 是通过 video 拿到视频第一帧的图片作为缩略图,代码我也贴在后面了

const handleChange = async (uploadFile, uploadFiles) => {
    const url = await generateVideo(uploadFile.raw)
    tempUploadFiles.value = uploadFiles

    fileList.value.push({
        name: uploadFile.name,
        url: url,
        raw: uploadFile.raw
    })
    // 实际渲染的是 uploadFiles 里面的url 而不是fileList的值
    // 另外一个坑是 多选的时候触发俩次该函数,但是 uploadFiles 值是一样的,需要根据name取到下标
    uploadFiles[uploadFiles.findIndex((item) => item.name === uploadFile.name)].url = url
    // console.log(fileList.value)
}
async function generateVideoThumbnail(file) {
    return new Promise((resolve, reject) => {
        const videoUrl = URL.createObjectURL(file)
        const video = document.createElement("video")
        const canvas = document.createElement("canvas")
        const ctx = canvas.getContext("2d")

        video.src = videoUrl
        video.muted = true
        video.crossOrigin = "anonymous"

        let completed = false

        const captureFrame = () => {
            if (completed) return
            completed = true
            try {
                canvas.width = video.videoWidth
                canvas.height = video.videoHeight
                ctx.drawImage(video, 0, 0)
                const thumbnailUrl = canvas.toDataURL("image/jpeg", 0.8)
                URL.revokeObjectURL(videoUrl)
                resolve(thumbnailUrl)
            } catch (error) {
                URL.revokeObjectURL(videoUrl)
                reject(error)
            }
        }

        video.addEventListener("loadeddata", () => {
            video.currentTime = 1
        })

        video.addEventListener("seeked", async () => {
            try {
                // 短暂播放确保帧渲染
                await video.play()
                setTimeout(() => {
                    video.pause()
                    captureFrame()
                }, 100)
            } catch (error) {
                // 如果播放失败,直接截图
                captureFrame()
            }
        })

        video.addEventListener("error", () => {
            if (!completed) {
                URL.revokeObjectURL(videoUrl)
                reject(new Error("视频加载失败"))
            }
        })

        setTimeout(() => {
            if (!completed) {
                URL.revokeObjectURL(videoUrl)
                reject(new Error("操作超时"))
            }
        }, 8000)

        video.load()
    })
}

export default generateVideoThumbnail

5. 阿里云自定义上传如何拿到 进度条

在我们使用 官方 给到的 ali-oss 库时,进度条是需要调用 分片上传才能传回进度条

代码示例:

import OSS from "ali-oss";

const ossClient = axios.get(this.url).then(token=>{
    this.client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  authorizationV4: true,
  // 填写Bucket名称。
  bucket: 'examplebucket',
});

const uploadPromises = fileList.value.map((file, index) => {
            tempUploadFiles.value[index].status = "uploading"
            return ossClient.client.multipartUpload(
                "your-path/" + file.name,
                file.raw || file, // 兼容不同格式
                {
                    // 获取分片上传进度、断点和返回值。
                    progress: (p) => {
                        console.log(p)
                        tempUploadFiles.value[index].percentage = Math.round(p * 100, 2)
                    },
                    // 设置并发上传的分片数量。
                    parallel: 4,
                    // 设置分片大小。默认值为1 MB,最小值为100 KB,最大值为5 GB。最后一个分片的大小允许小于100 KB。
                    partSize: 1024 * 1024
                }
            )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值