前端直传阿里云oss的图片媒体库插件

316 阅读2分钟

环境: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

服务端签名后直传

PostObject

本文采用的方式是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组件等。