手记

基于nuxt和iview搭建OM后台管理系统实践(3)-阿里oss上传组件的封装

封面图,基于创客贴在线制作

目录结构

这是《基于nuxt和iview搭建OM后台管理系统实践》这一个系列文章的目录,大致思路如下:

前言

上一篇记录了quill富文本的封装过程,这一篇开始讲解上传组件(七牛、阿里云oss)的封装。

看东西

如动图所示,为上传组件演示,可以看到组件有上传、预览、删除重新上传、文件大小校验等功能。


上传组件演示

阿里oss上传组件实现过程

实现原理:用input[type='file']标签,并绑定一个change事件实现选择本地电脑文件操作,同时通过其他button触发input的change事件,最终与阿里oss进行交互实现上传图片的功能。

步骤1:引入阿里云osssdk代码,需要注意的是:框架使用的nuxt,引入sdk需要按照nuxt的规范在head方法里引入,附上head方法使用文档地址

// 文件 components/upload.vue<template><!--省略业务代码--></template><script>export default {  head: {    script: [{ src: "http://gosspublic.alicdn.com/aliyun-oss-sdk.min.js" }]//引入sdk
  },
<script><style>/*省略样式代码*/</style>

步骤2:获取上传token,后端提供接口,因token有时效性故每次上传操作时需向后端请求;

// 文件 components/upload.vue<template><!--省略业务代码--></template><script>import axios from "~/plugins/axios";export default {  head: {    script: [{ src: "http://gosspublic.alicdn.com/aliyun-oss-sdk.min.js" }]//引入sdk
  },  method:{
      doUpload() {          const _this = this;          const urls = [];          this.loading = true;
          axios.get("/api/m/common/oss/getproperties") 
          .then(res=>{            //向后端请求获取oss token等信息
              _this.ossKey.AccessKeyId = res.data.data.AccessKeyId;
              _this.ossKey.AccessKeySecret = res.data.data.AccessKeySecret;
              _this.ossKey.BucketName = res.data.data.BucketName;
              _this.ossKey.SecurityToken = res.data.data.SecurityToken;              
            //与阿里oss交互,上传文件到服务器并返回文件路径
          })
      }
  }
<script><style>/*省略样式代码*/</style>

步骤3:与阿里oss交互,上传文件到服务器并返回文件路径;

//postOss(){    const _this = this;    const client = new window.OSS.Wrapper({        region: _this.region,        accessKeyId: _this.ossKey.AccessKeyId,        accessKeySecret: _this.ossKey.AccessKeySecret,        stsToken: _this.ossKey.SecurityToken,        bucket: _this.ossKey.BucketName
    });
    _this.percentage = 0;    const files = document.getElementById(_this.id);    if(files.files[0].size > _this.limitSize){//对文件大小进行校验超出弹出提示框
        _this.$Notice.warning({            title: '温馨提示',            desc:  '文件超出'+_this.limitSize/1024+'kb限制,请压缩一下图片再上传'
        });
        _this.loading = false;        return false;
    }    if (files.files) {        const fileLen = document.getElementById(_this.id).files;        let resultUpload = "";        for (let i = 0; i < fileLen.length; i++) {            const file = fileLen[i];             // 随机命名
            let random_name ="mapOm/" + random_string(6) + "_" + new Date().getTime() + "." + file.name.split(".").pop();              // 上传
            client.multipartUpload(random_name, file, {                progress: function*(percentage, cpt) {                    // 上传进度
                    _this.percentage = percentage;
                }
            })
            .then(results => {                // 上传完成
                _this.loading = false;
                 _this.show = true;                 const url = "http://sinochem-agri-fr.oss-cn-beijing.aliyuncs.com/" + results.name;
                 _this.url = url;
                _this.$emit('uploadedUrl',results.name);//把url传给父组件
            })
            .catch(err => {
                _this.loading = false;                console.log(err);
            });
        }
    }
}

步骤4:引用并使用组件;

import uploadImg from '~/components/upload';//引入组件<upload-img label="土壤温度" id="soilTemperature"
    @uploadedUrl="(url) => this.formItem.trend.soilTemperature = url"
    @remove="() => this.formItem.trend.soilTemperature = ''"></upload-img>

阿里oss上传组件完整代码

<template>
    <FormItem :label="label">
          <template  v-if="!edit">
            <input :id="id" ref="input" @change="doUpload" class="file" type="file">
            <div class="demo-upload-list" v-if="show">
              <img :id="'img_'+id"  :src="url" width="50px" height="50px">
              <div class="demo-upload-list-cover">
                <Icon type="ios-eye-outline" @click.native="handleView"></Icon>
                <Icon type="ios-trash-outline" @click.native="handleRemove"></Icon>
              </div>
            </div>
            <Button v-if="!show" :loading="loading" type="ghost" icon="ios-cloud-upload-outline" @click="upload">{{placeholder}}</Button>
            <Modal :title="label+'预览'" v-model="visible">
              <img :src="url" v-if="visible" style="width:100%;height:auto;">
            </Modal>
          </template>
    
          <!-- 预览 -->
          <template  v-else>
            <div class="demo-upload-list">
              <img :id="'img_'+id"  :src="editUrl" width="50px" height="50px">
              <div class="demo-upload-list-cover">
                <Icon type="ios-eye-outline" @click.native="handleView"></Icon>
                <Icon type="ios-trash-outline" @click.native="handleRemove"></Icon>
              </div>
            </div>
            <Modal :title="label+'预览'" v-model="visible">
              <img :src="editUrl" v-if="visible" style="width:100%;height:auto;">
            </Modal>
          </template>
    </FormItem></template><script>import axios from "~/plugins/axios";import { random_string } from "~/lib/utils";export default {  head: {    script: [{ src: "http://gosspublic.alicdn.com/aliyun-oss-sdk.min.js" }]
  },  props: {    editUrl: {      default: ""
    },    showUploadList: {      type: Boolean,      default: true
    },    action: {      default: ""
    },    label: {      default: "上传组件"
    },    placeholder: {      default: "上传图表"
    },    id: {      default: "upload"
    },    limitSize: {      default: 102400
    }
  },  name: "upload",
  data() {    return {      loading: false,      visible: false,      show: false,      region: "oss-cn-beijing",      percentage: 0,      url: "",      urls: [],      fileList: [],      ossKey: {},      edit: false
    };
  },
  created() {},
  mounted() {},  methods: {
    doUpload() {      const _this = this;      const urls = [];      this.loading = true;

      axios
        .get("/api/getproperties")
        .then(res => {
          _this.ossKey.AccessKeyId = res.data.data.AccessKeyId;
          _this.ossKey.AccessKeySecret = res.data.data.AccessKeySecret;
          _this.ossKey.BucketName = res.data.data.BucketName;          // _this.ossKey.Endpoint = res.data.data.Endpoint;
          _this.ossKey.SecurityToken = res.data.data.SecurityToken;          //上传
          const client = new window.OSS.Wrapper({            region: _this.region,            accessKeyId: _this.ossKey.AccessKeyId,            accessKeySecret: _this.ossKey.AccessKeySecret,            stsToken: _this.ossKey.SecurityToken,            bucket: _this.ossKey.BucketName
          });
          _this.percentage = 0;          const files = document.getElementById(_this.id);          if (files.files[0].size > _this.limitSize) {
            _this.$Notice.warning({              title: "温馨提示",              desc:                "文件超出" +
                _this.limitSize / 1024 +                "kb限制,请压缩一下图片再上传"
            });
            _this.loading = false;            return false;
          }          if (files.files) {            const fileLen = document.getElementById(_this.id).files;            let resultUpload = "";            for (let i = 0; i < fileLen.length; i++) {              const file = fileLen[i];              // 随机命名
              let random_name =                "mapOm/" +
                random_string(6) +                "_" +                new Date().getTime() +                "." +
                file.name.split(".").pop();              // 上传
              client
                .multipartUpload(random_name, file, {                  progress: function*(percentage, cpt) {                    // 上传进度
                    _this.percentage = percentage;
                  }
                })
                .then(results => {                  // 上传完成
                  _this.loading = false;
                  _this.show = true;                  const url =                    "http://sinochem-agri-fr.oss-cn-beijing.aliyuncs.com/" +
                    results.name;
                  _this.url = url;
                  _this.$emit("uploadedUrl", results.name); //把url传给父组件
                })
                .catch(err => {
                  _this.loading = false;                  console.log(err);
                });
            }
          }
        })
        .catch(errro => {          this.$Notice.error({            title: "温馨提示",            desc: "网络请求失败,请稍后再试"
          });
          _this.loading = false;          console.log(errro);
        });
    },
    upload() {      var av = document.getElementById(this.id);
      av.click();
    },
    handleView() {    //预览
      this.visible = true;
    },
    handleRemove() {    //删除图片
      const _this = this;      if (_this.edit == true) {
        _this.edit = false;
        _this.$emit("remove");
      } else {
        _this.visible = false;
        _this.show = false;
        _this.$emit("remove");
      }
    }
  },  watch: {
    url(val) {      if (val) {        this.urls.push(val);
      }
    },
    editUrl() {      if (this.editUrl != null && this.editUrl != "") {        this.edit = true;
      }
    }
  }
};</script><style scoped>.file {  display: none;
}.demo-upload-list {  display: inline-block;  width: 60px;  height: 60px;  text-align: center;  line-height: 60px;  border: 1px solid transparent;  border-radius: 4px;  overflow: hidden;  background: #fff;  position: relative;  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);  margin-right: 4px;
}.demo-upload-list img {  width: 100%;  height: 100%;
}.demo-upload-list-cover {  display: none;  position: absolute;  top: 0;  bottom: 0;  left: 0;  right: 0;  background: rgba(0, 0, 0, 0.6);
}.demo-upload-list:hover .demo-upload-list-cover {  display: block;
}.demo-upload-list-cover i {  color: #fff;  font-size: 20px;  cursor: pointer;  margin: 0 2px;
}</style>

总结

iview官方提供了一个上传组件,但是不符合我们实际需求,我查看了源码并在此基础上进行了二次封装最终实现了需求。现在再回过头去看写的代码发现有点乱,后续抽空会进行代码优化。同时要吐槽下阿里oss文档,都没有一个demo让开发者查看,显得很不友好。



作者:愿爱无忧dk_
链接:https://www.jianshu.com/p/3714417697fb

0人推荐
随时随地看视频
慕课网APP