服务端签名,web端直传阿里云OSS的Vue插件实现

阅读次数: 841

  • A+
所属分类:建站

环境:Nuxt.js(Vue全家桶+webpack+bable)

组件库:element.ui

插件适用场景:脱离了页面布局的交互页面,类似于对话框、抽屉

全局调用插件的实现原理:

  • 利用element.ui的dialog组件,实现页面的显示、关闭
<template>
    <el-dialog :visible.sync="show">
        <button @click="close">取消</button>
        <button @click="sure">确定</button>
    </el-dialog>
</template>
name: "ImgUpload",
props: {
    //将vue实例传入,this指针。若组件内有使用Vue实例的数据或方法,则此参数为必须
    that: {
      type: Object
    }
},
data() {
    return {
      show: false,
    }
},
methods:{
    //初始化
    confirm() {
      this.show = true;
      return new Promise((resolve, reject) => {
        this.promiseStatus = { resolve, reject };
      });
    },
    //取消,关闭页面
    close(){
      this.show = false;
      //点击取消后在此传数据给页面
      this.promiseStatus && this.promiseStatus.reject(//数据) 
    },
    //确定,关闭页面
    sure(){
      this.show = false;
      //点击确定后在此传数据给页面
      this.promiseStatus && this.promiseStatus.resolve(//数据) 
    }
}
  • 将写好的vue组件以函数的形式挂载到vue原型上
import Vue from "vue";
import ImgUpload from "./ImgUpload.vue";
const Vuecomponent = Vue.extend(ImgUpload);
const vm = new Vuecomponent().$mount();
let init = false;
const install = options => {
  Object.assign(vm, options);
  if (!init) {
    document.body.appendChild(vm.$el);
    init = true;
  }
  return vm.confirm();
};
​
export default install;
import ImgUpload from "@/components/ImgUpload.js";
Vue.prototype.$imgUpload = ImgUpload;
  • 调用方式
<template>
    <button @click="imgUpload">选择相片</button>
</template>
<script>
export default {
  methods: {
    imgUpload(){
      this.$imgUpload({that:this}).then(res=>{console.log(res);});
    },
  }
};
</script>

服务器签名,web端直接上传图片至阿里云OSS

web端上传文件至阿里云OSS的三种方式,及相关规则限制如下

[web端上传数据到阿里云OSS]  https://help.aliyun.com/document_detail/112718.html?spm=a2c4g.11186623.6.1711.51e04d52TZwRRY 

[服务端签名后直传]  https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1718.8ecd6843ilGhvQ 

[PostObject​]  https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.2.12.6a0a6843Vt9fM9#reference-smp-nsw-wdb 

本文采用的方式是PostObjecj,通过HTML表单上传的方式将文件(Object)上传至指定存储空间(Bucket)。

因为阿里云的文件上传只能一张一张上传,且服务端每次传回的key值(文件路径)每次都会变动。所以,通过循环文件列表的方式,逐次向服务器请求签名,并以表单的形式上传至阿里云OSS,上传完成之后,再统一将图片路径传回给服务器。

注1:因为服务器传回的host地址可能变更,所以,本文没有将host地址配置进nuxt的全局环境中。

注2:为了代码编写,axios配置了前缀/api,所以,采用了原生ajax。

<script>
export default {
  methods: {
    //用户选择好了图片并点击上传
    upload() {
      let vim = this.that;
      let _this = this;
      //上传前向服务器发起请求,询问是否能上传
      vim.$canUpload({ album_id: this.album_id }).then(res => {
        if (res.data.code === 200) {
          postObject();
        } else {
          vim.$message.info("该相册不可上传图片");
        }
      });
      //利用formData上传至阿里OSS
      function postObject() {
        _this.uploadPicFile.forEach((pic, index) => {
          vim.$getOSS().then(secret => {
            let SECRET = secret.data;
            let filename = "-" + pic.width + "*" + pic.height + pic.type;
            let formData = new FormData();
            formData.append("key", SECRET.key + filename); //存储在oss的文件路径+文件名
            formData.append("OSSAccessKeyId", SECRET.accessid); //accessKeyId
            formData.append("policy", SECRET.policy); //policy
            formData.append("Signature", SECRET.signature); //签名
            formData.append("success_action_status", 200); //成功后返回的操作码
            formData.append("file", pic.file); //文件
            let xhr = new XMLHttpRequest();
            xhr.open("POST", "https://" + SECRET.host, true);
            xhr.onload = function() {
              if (xhr.status === 200) {
                pic.wholePath = SECRET.host + "/" + SECRET.key + filename; //图片全路径
              } else {
                vim.$message.error("部分图片上传失败");
              }
              //上传完最后一张后统一将图片信息传给服务器
              if (index === _this.uploadPicFile.length - 1) {
                postPicInfo();
              }
            };
            xhr.send(formData);
          });
        });
      }
      //将图片路径及相关信息统一传给服务器
      function postPicInfo() {
        let successPics = _this.uploadPicFile.filter(ele => {
          return Object.keys(ele).includes("wholePath");
        });
        let data = {};
        successPics.forEach((pic, index) => {
          data[`insert[${index}][pic_name]`] = pic.name;
          data[`insert[${index}][pic_desc]`] = pic.name;
          data[`insert[${index}][album_name]`] = _this.albumName;
          data[`insert[${index}][album_id]`] = _this.albumId;
          data[`insert[${index}][pic_url]`] = pic.wholePath;
        });
        vim.$addPic(data).then(res => {
          if (res.data.code === 200) {
            vim.$message.success("图片上传成功");
          }
        });
      }
    }
  }
};
</script>
可思考方向:采用antd组件库的upload组件等。
  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: