封面图,基于创客贴在线制作
目录结构
这是《基于nuxt和iview搭建OM后台管理系统实践》这一个系列文章的目录,大致思路如下:
自行开发的公共组件,富文本quill[已完成]、地图、上传组件的封装过程
项目上线流程,自动化打包(Jenkins)
项目总结,总结开发过程中的坑点,避免以后再掉坑
前言
上一篇记录了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