vue2+element-ui 实现OSS分片上传+取消上传

  • 遇到问题:项目中需要上传500MB以上的视频。一开始使用上传组件el-upload,调用后台接口,但是出现了onprogress显示百分百后接口一直pending,过了很多秒后接口才通,如果遇到大文件的话,接口就会报超时。

  • 解决办法:
    使用阿里云OSS的分片上传。调用OSS时报No’Access-Control-Allow-Origin’的错误
    一定要设置跨域规则!!!否则会报No’Access-Control-Allow-Origin’的错误

image.png

1. 创建oss.js文件

let OSS = require('ali-oss');

let client = new OSS({
  region: '', // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  accessKeyId: '',
  accessKeySecret: '',
  bucket: '', // 填写Bucket名称
});

let cdnUrl = '' // 文件上传后的回调地址

export { client, cdnUrl };

2. 创建一个上传视频组件 VideoUpload.vue

<template>
  <div class="component-upload-image">
    <el-upload action="" :http-request="beforeUpload" class="avatar-uploader" :limit="limit"
      :on-error="handleUploadError" :on-exceed="handleExceed" name="file" :show-file-list="false" :file-list="fileList"
      ref="uploadRef">
      <video v-if="videoForm.showVideoPath && !videoFlag" :src="videoForm.showVideoPath" class="avatar video-avatar"
        controls="controls">
        您的浏览器不支持视频播放
      </video>
      <!-- //i标签是上传前的那个+上传后隐藏 -->
      <i v-else-if="!videoForm.showVideoPath && !videoFlag" class="el-icon-plus avatar-uploader-icon"></i>
      <el-progress v-if="videoFlag == true" type="circle" :percentage="videoUploadPercent"
        style="margin-top: 7px"></el-progress>
    </el-upload>
    <el-button v-if="isShowBtn && videoForm.showVideoPath" class="mt-20" plain round @click="handleDelete" size="small"
      type="primary">重新上传<i class="el-icon-upload el-icon--right"></i></el-button>
  </div>
</template>

<script>
import { client, cdnUrl } from "./oss";

export default {
  props: {
    value: [String, Object, Array],
    // 图片数量限制
    limit: {
      type: Number,
      default: 1,
    },
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 5120,
    },
    fileType: {
      type: Array,
      default: () => ["video/*"],
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true,
    },
    // 是否显示进度条
    isShowUploadVideo: {
      type: Boolean,
      default: false,
    },
    // 是否显示重新上传按钮
    isShowBtn: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      dialogImageUrl: "",
      dialogVisible: false,
      // hideUpload: false,
      // baseUrl: process.env.VUE_APP_BASE_API,
      // uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
      fileList: [],
      videoForm: {
        showVideoPath: "", //回显的变量
      },
      videoFlag: false,
      videoUploadPercent: 0,
      isCancel: false
    };
  },
  watch: {
    value: {
      handler(val) {
        if (val) {
          this.videoForm.showVideoPath = val;
          // 首先将值转为数组
          const list = Array.isArray(val) ? val : this.value.split(",");
          // 然后将数组转为对象数组
          this.fileList = list.map((item) => {
            if (typeof item === "string") {
              item = { name: item, url: item };
            }
            return item;
          });
        } else {
          this.fileList = [];
          return [];
        }
      },
      deep: true,
      immediate: true,
    },
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
  },
  methods: {
    //自定义上传方法..
    Upload(file) {
      debugger;
      //判断扩展名
      const tmpcnt = file.file.name.lastIndexOf(".");
      const exname = file.file.name.substring(tmpcnt + 1);
      //  配置路径以及文件名称
      const fileName = "files/" + file.file.uid + "." + exname;
      const progress = (p, _checkpoint) => {
        this.videoFlag = true;
        this.videoUploadPercent = Number((Number(p) * 100).toFixed(1));
        console.log(this.isCancel);
        if (this.isCancel) {
          console.log("取消上传");
          client.cancel();
          this.isCancel = false;
        }
      };
      client.multipartUpload(fileName, file.file, {
        progress,
        // 设置并发上传的分片数量。
        // parallel: 4,
        // 设置分片大小。默认值为1 MB,最小值为100 KB。
        partSize: 5 * 1024 * 1024,
      }).then((res) => {
        // console.log(res, "res");
        this.videoFlag = false;
        if (res.name) {
          this.videoForm.showVideoPath = cdnUrl + res.name;
          this.$emit("input", this.videoForm.showVideoPath, this.duration);
          // this.loading.close();
        } else {
          this.$modal.msgError("上传视频失败,请重试");
          // this.loading.close();
          this.handleDelete();
        }
      })
        .catch((err) => {
          console.log(err);
          if (err.name == 'cancel') {
            this.$message('上传取消');
          } else {
            this.$modal.msgError(err);
          }
          this.handleDelete();
        });
    },
    handleDelete() {
      this.isCancel = true;
      this.videoFlag = false;
      this.$refs.uploadRef.clearFiles();
      this.duration = 0;
      this.videoForm.showVideoPath = "";
      this.$emit("input", this.videoForm.showVideoPath, this.duration); // 清除已上传的文件
    },
    // 上传前
    beforeUpload(file) {
      var fileSize = file.file.size / 1024 / 1024 < this.fileSize; //控制大小  修改50的值即可
      console.log(file.file.type);
      if (
        this.fileType.indexOf(file.file.type) == -1 //控制格式
      ) {
        this.$modal.msgError(
          `文件格式不正确, 请上传${this.fileType.join("/")}视频格式文件!`
        );
        return false;
      }
      if (!fileSize) {
        this.$modal.msgError(`上传视频大小不能超过 ${this.fileSize} MB!`);
        return false;
      }
      // 获取视频时长
      var url = URL.createObjectURL(file.file);
      var audioElement = new Audio(url);
      var time;
      var that = this;
      audioElement.addEventListener("loadedmetadata", function () {
        time = audioElement.duration; //时长为秒
        that.duration = time;
      });
      // 一开始设置的全屏遮罩层,考虑到用户可能想取消上传,于是去除
      // this.loading = this.$loading({
      //   lock: true,
      //   text: "上传中",
      //   background: "rgba(0, 0, 0, 0.7)",
      // });
      this.Upload(file);
    },
    // 文件个数超出
    handleExceed() {
      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
    },
    // 上传失败
    handleUploadError() {
      this.$modal.msgError("上传失败,请重试");
      // this.loading.close();
    },
  },
};
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hideUpload .el-upload--picture-card {
  display: none;
}

::v-deep .el-upload--picture-card {
  width: 104px;
  height: 104px;
  line-height: 104px;
}

::v-deep .el-upload-list--picture-card .el-upload-list__item {
  width: 104px;
  height: 104px;
}

.avatar-uploader-icon {
  border: 1px dashed #d9d9d9 !important;
}

.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9 !important;
  border-radius: 6px !important;
  position: relative !important;
  overflow: hidden !important;
}

.avatar-uploader .el-upload:hover {
  border: 1px dashed #d9d9d9 !important;
  border-color: #409eff;
}

.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 300px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}

.avatar {
  width: 300px;
  height: 178px;
  display: block;
}
</style>


在父组件中调用

<template>
  <div class="app-container">
    <el-dialog title="" :visible.sync="open" append-to-body @close="cancel">
    	<VideoUpload v-model="formClass.ossUrl" :limit="1" :fileType="fileType" :fileSize="5120" :isShowUploadVideo="true" @input="uploadVideo" ref="videoUploadRef" :isShowBtn="true"></VideoUpload>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      open: false,
      formClass: {
        ossUrl: "", //阿里云oss地址-视频
      },
      fileType: ["video/mp4"],
    };
  },
  methods: {
    submitForm() {},
    cancel() {
      if (this.$refs.videoUploadRef) {
        this.$refs.videoUploadRef.handleDelete();
      }
      this.open = false;
    },
  },
};
</script>

原文链接:https://blog.csdn.net/wcy0112/article/details/136843100

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/514482.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【javaScript】DOM编程入门

一、什么是DOM编程 概念&#xff1a;DOM(Document Object Model)编程就是使用document对象的API完成对网页HTML文档进行动态修改&#xff0c;以实现网页数据和样式动态变化的编程 为什么要由DOM编程来动态修改呢&#xff1f;我们就得先理解网页的运行原理&#xff1a; 如上图&a…

机器学习每周挑战——信用卡申请用户数据分析

数据集的截图 # 字段 说明 # Ind_ID 客户ID # Gender 性别信息 # Car_owner 是否有车 # Propert_owner 是否有房产 # Children 子女数量 # Annual_income 年收入 # Type_Income 收入类型 # Education 教育程度 # Marital_status 婚姻状况 # Housing_type 居住…

C_C++数据的在内存中的分布

C/C内存分布 在编程世界中&#xff0c;C和C语言一直以其强大的性能和灵活性著称。然而&#xff0c;这种强大和灵活的背后&#xff0c;离不开对内存分布的深入理解和熟练掌握。本文将详细介绍C/C程序中的内存分布&#xff0c;包括栈、堆和全局变量的存储区域。下面是c/c中&…

如何在本地搭建集成大语言模型Llama 2的聊天机器人并实现无公网IP远程访问

文章目录 1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 随着ChatGPT 和open Sora 的热度剧增,大语言模型时代,开启了AI新篇章,大语言模型的应用非常广泛&#xff0c;包括聊天机…

x-cmd-pkg | broot 是基于 Rust 开发的一个终端文件管理器

简介 broot 是基于 Rust 开发的一个终端文件管理器&#xff0c;它设计用于帮助用户在终端中更轻松地管理文件和目录&#xff0c;使用树状视图探索文件层次结构、操作文件、启动操作以及定义您自己的快捷方式。 同时它还集成了 ls, tree, find, grep, du, fzf 等工具的常用功能…

Python爬虫之分布式爬虫

分布式爬虫 1.详情介绍 分布式爬虫是指将一个爬虫任务分解成多个子任务&#xff0c;在多个机器上同时执行&#xff0c;从而加快数据的抓取速度和提高系统的可靠性和容错性的技术。 传统的爬虫是在单台机器上运行&#xff0c;一次只能处理一个URL&#xff0c;而分布式爬虫通过将…

Android Glide配置AppGlideModule定制化线程池,Kotlin(1)

Android Glide配置AppGlideModule定制化线程池&#xff0c;Kotlin&#xff08;1&#xff09; plugins {id org.jetbrains.kotlin.kapt }implementation com.github.bumptech.glide:glide:4.16.0kapt com.github.bumptech.glide:compiler:4.16.0 import android.content.Context…

C之结构体初始化10种写法总结(九十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

开启 Keep-Alive 可能会导致http 请求偶发失败

大家好&#xff0c;我是蓝胖子&#xff0c;说起提高http的传输效率&#xff0c;很多人会开启http的Keep-Alive选项&#xff0c;这会http请求能够复用tcp连接&#xff0c;节省了握手的开销。但开启Keep-Alive真的没有问题吗&#xff1f;我们来细细分析下。 最大空闲时间造成请求…

跨境金融区块链服务平台

跨境金融服务是因企业及个人跨境经营、交易、投资、往来等活动而产生的资金使用、调拨、配置等需求&#xff0c;而提供的金融服务。近年来&#xff0c;随着我国经济的快速稳步增长和全球化经济一体化的不断深入发展&#xff0c;跨境金融业务增长迅速&#xff0c;监管也开始转化…

在ChatGPT中,能用DALL·E 3编辑图片啦!

4月3日&#xff0c;OpenAI开始向部分用户&#xff0c;提供在ChatGPT中的DALLE 3图片编辑功能。 DALLE 3是OpenAI在2023年9月20日发布的一款文生图模型&#xff0c;其生成的图片效果可以与Midjourney、leonardo、ideogram等顶级产品媲美&#xff0c;随后被融合到ChatGPT中增强其…

反截屏控制技术如何防止信息通过手机拍照泄漏?

反截屏控制技术为企业数据安全提供了重要的防护措施。通过以下几点&#xff0c;有效阻止了信息通过拍照等方式的泄漏&#xff1a; 反截屏控制开启&#xff0c;用户启动截屏操作时&#xff0c;允许非涉密内容截屏操作&#xff0c;但所有涉密内容窗口会自动隐藏&#xff0c;防止涉…

记录一次threejs内存泄露问题排查过程

问题描述&#xff1a; 一个有关地图编辑的使用threejs的这样的组件&#xff0c;在多次挂载销毁后&#xff0c;页面开始卡顿。 问题排查&#xff1a; 1. 首先在chrome dev tool中打开performance monitor面板&#xff0c;观察 JS head size、DOME Nodes、Js event listeners数…

AWVS 安装详细教程

一、软件介绍 Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的Web网络漏洞扫描工具&#xff0c;它通过网络爬虫测试你的网站安全&#xff0c;检测流行安全漏洞。AWVS官方网站是&#xff1a;http://www.acunetix.com/ 二、下载安装 官方下载地址&#xff1a;https…

【大数据存储】yolov3识虫实验

一、项目实践步骤 图 1 构建模型和完成训练的程序图 二、实验背景 2.1数据集介绍 AI识虫数据集结构如下&#xff1a; 提供了2183张图片&#xff0c;其中训练集1693张&#xff0c;验证集245&#xff0c;测试集245张。包含7种昆虫&#xff0c;分别是Boerner、Leconte、Linnaeus…

​如何使用ArcGIS Pro进行洪水淹没分析

洪水淹没分析是一种常见的水文地理信息系统应用&#xff0c;用于模拟和预测洪水事件中可能受到淹没影响的地区&#xff0c;这里为大家介绍一下ArcGIS Pro进行洪水淹没分析的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的DEM数据&…

搞学术研究好用免费的学术版ChatGPT网站-学术AI

https://chat.uaskgpt.com/mobile/?user_sn88&channelcsdn&sceneloginhttps://chat.uaskgpt.com/mobile/?user_sn88&channelcsdn&scenelogin 推荐一个非常适合中国本科硕士博士等学生老师使用的学术版ChatGPT&#xff0c; 对接了超大型学术模型&#xff0c…

linux------jekins构建cicd

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;linux &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#…

【动态规划】【背包问题】基础背包

【动态规划】【01背包问题】 解法 二维dp数组01背包解法 一维dp数组&#xff08;滚动数组&#xff09;01背包 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法 二维dp数组01背包 &#x1f612;: 我的代码实现> …

操作系统导论课后作业-第十七章答案

课程作业-第十七章&#xff1a; 17.1首先以标志flag -n 10 -H 0 -p BEST -s 0运行程序来产生一些随机的分配和空闲。你能预测malloc()/free()会返回什么吗&#xff1f;你可以在每次请求后猜测空闲列表的状态吗&#xff1f;随着时间的推移&#xff0c;你对空闲列表有什么发现&a…