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

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

遇到问题:
项目中需要上传500MB以上的视频。一开始使用上传组件el-upload,调用后台接口,但是出现了onprogress显示百分百后接口一直pending,过了很多秒后接口才通,如果遇到大文件的话,接口就会报超时。
解决办法:
使用阿里云OSS的分片上传。调用OSS时报No’Access-Control-Allow-Origin’的错误
一定要设置跨域规则!!!否则会报No’Access-Control-Allow-Origin’的错误
如果有安全设置不能如下设置,那么把项目的正式环境和测试环境加入白名单中即可
在这里插入图片描述

接下来是实现代码:
先装包 npm install --save ali-oss

  1. 创建oss.js文件
    不过accessKeyIdaccessKeySecret直接写在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 };
  1. 创建一个上传视频组件 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) {
      this.isCancel = false;
      //判断扩展名
      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();
        }
      };
      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>

  1. 在父组件中调用(我这边是全局引用了)
<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>
  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Element-UI 是一个基于 Vue.js 的组件库,提供了丰富的 UI 组件和交互功能。要实现Element-UI上传图片到阿里云 OSS,可以按照以下步骤进行: 1. 安装依赖:首先,需要安装 `ali-oss` 和 `element-ui` 的相关依赖。可以使用 npm 或者 yarn 进行安装。 2. 配置阿里云 OSS:在阿里云 OSS 控制台创建一个 Bucket,并获取 AccessKeyId、AccessKeySecret、Bucket 名称和 Endpoint。 3. 创建上传组件:在 Vue 组件中,使用 Element-UI 的 `el-upload` 组件来实现图片上传功能。可以设置 `action` 属性为阿里云 OSS上传地址,`before-upload` 属性来处理上传前的逻辑。 4. 在上传前进行签名:在 `before-upload` 方法中,需要通过阿里云 OSS 的 SDK 进行签名操作,生成上传所需的参数。可以使用 `ali-oss` 库提供的 `put` 方法来进行签名。 5. 上传图片:在签名成功后,调用 `put` 方法将图片上传到阿里云 OSS。可以设置 `on-success` 属性来处理上传成功后的逻辑。 下面是一个简单的示例代码: ```vue <template> <el-upload action="https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" > <el-button>点击上传</el-button> </el-upload> </template> <script> import OSS from 'ali-oss'; export default { methods: { async handleBeforeUpload(file) { const client = new OSS({ region: 'your-region', accessKeyId: 'your-access-key-id', accessKeySecret: 'your-access-key-secret', bucket: 'your-bucket-name', }); try { const result = await client.put(file.name, file); // 在这里可以处理上传成功后的逻辑 } catch (error) { // 处理上传失败的逻辑 } // 返回 false 可以阻止上传 return false; }, handleUploadSuccess(response) { // 处理上传成功后的逻辑 }, }, }; </script> ``` 请注意,上述代码中的 `your-region`、`your-access-key-id`、`your-access-key-secret` 和 `your-bucket-name` 需要替换为你自己的阿里云 OSS 相关信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值