本文是自己平时业务需求中的总结,如果你需要借鉴本文,那么你的上传行为应该是:
项目中下载ali-oss
依赖,我这里使用的是^6.0.1
版本
使用阿里云oss,将图片上传到阿里云,然后阿里云将图片地址返回,我们拿到图片地址,将它传递给后端
本文主要使用this.$refs.upload.uploadFiles
,获取到,el-upload
上传组件中的默认上传列表,无论上传失败还是成功,都会将图片保存在这里,所以我们只需要对他进行操作,就能实现我们想要的功能
1. 初始化阿里云对象,并获取阿里云token,用于上传图片
这里我把初始化阿里云的过程,写在一个js文件中,因为用到的地方比较多,如果你使用的次数比较少,你也可以直接写在页面中
(闲的没事还写了个随机生成文件名的函数,用于保证上传的每个文件有一个独一无二的文件名)
// 用于上传,图片文件
import { get } from '@/utils/request';
var moment = require('moment');
var client = '123';
// 初始化阿里云OSS
export function uploadOSS() {
return get('这里应该是一个后端的url,用于获取阿里云token').then((res) => {
if (res.data.result === '01') {
client = new OSS.Wrapper({
secure: true,
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: 'oss-cn-hangzhou',
// 填写Bucket名称。
bucket: 'wuneng-public',
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: res.data.data.keyid,
accessKeySecret: res.data.data.keysecret,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: res.data.data.token,
});
return client;
}
});
}
// 生成随机的文件名,文件名包括【随机6位大写英文字母】+【当前时间,年月日时分秒】
export function randomFileName() {
var result = [];
for (var i = 0; i < 6; i++) {
// 生成一个0到25的数字,向上取整
var ranNum = Math.ceil(Math.random() * 25);
// 大写字母'A'的ASCII是65,A~Z的ASCII码就是65 + 0~25,然后调用String.fromCharCode()传入ASCII值返回相应的字符并push进数组里
result.push(String.fromCharCode(65 + ranNum));
}
// 上传时间的时间,年月日时分秒的字符串
const dateStr = moment().format('YYYYMMDDhhmmss');
// 随机的六位大写英文单词
const randomStr = result.join('');
return randomStr + dateStr;
}
2. 组件编写、
这是一个完整的组件,可以直接拿来用的,注释写的也很清楚
你的项目中需要有:axios依赖,阿里云依赖,element-ui依赖,moment.js依赖
<template>
<div>
<!-- 预览图片dialog,模态框 -->
<el-dialog :visible.sync="innerVisible" :show-close="false" append-to-body>
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<!-- 上传组件 -->
<!-- http-request 覆盖默认上传行为,使用自定义上传行为 -->
<!-- action 必填项,但是这里我们使用自定义上传模式,这里可以直接为空 -->
<!-- list-type 文件列表的类型,这里使用的是 picture-card 图片卡的形式 -->
<!-- accept 接受上传的文件类型,接收类型执行搜索 -->
<!-- limit 最大上传数量 -->
<el-upload ref="upload" :http-request="handleUpload" action="" list-type="picture-card" accept="image/*" :limit="3">
<i slot="default" class="el-icon-plus"></i>
<!-- 操作按钮,包括【图片预览、删除】 -->
<div slot="file" slot-scope="{ file }">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
<i class="el-icon-zoom-in"></i>
</span>
<span class="el-upload-list__item-delete" @click="handleDownload(file)">
<i class="el-icon-download"></i>
</span>
<span class="el-upload-list__item-delete" @click="handleRemove(file)">
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
</div>
</template>
<script>
// 引入【初始化阿里云】【随机生成文件名】的函数
import { uploadOSS, randomFileName } from '@/utils/uploadOSS.js';
import axios from 'axios';
export default {
data() {
return {
// 预览时,图片的url
dialogImageUrl: '',
// 预览框dialog是否展示,默认false,隐藏
innerVisible: false,
// 图片文件列表,这个fileList是我自己定义的,不是组件的那个fileList,不要搞混
fileList: [],
};
},
mounted() {
// 生命周期,初始化阿里云
this.handleUploadOSS();
},
methods: {
handleUploadOSS() {
uploadOSS().then((res) => {
// 将阿里云oss的参数,返回并赋值给client
this.client = res;
});
},
// 自定义上传动作
async handleUpload(file) {
// multipartUpload函数,第一个参数是文件名,第二个参数是文件,第三个参数,是否显示上传进度
const result = await this.client.multipartUpload(randomFileName() + file.file.name, file.file);
if (result.res.status != 200) {
this.$message.error('上传失败!');
return;
}
this.$message.success('上传成功!');
console.log(result.res.requestUrls[0]);
var tempUrl = '';
// 上传大图片,返回的url后面会出现uploadId的情况,这时候要把uploadId去掉(应该还有更好的方法去掉uploadId,这里我就先这样处理,有兴趣的可以自己探索)
// 例如:https://wuneng-public.oss-cn-hangzhou.aliyuncs.com/VLRQUU2021111008402692573817_p0.jpg?uploadId=EC63D28587914C8698076C93BEA16A80
if (result.res.requestUrls[0].indexOf('?uploadId=') != -1) {
tempUrl = result.res.requestUrls[0].split('?uploadId=')[0];
} else {
tempUrl = result.res.requestUrls[0];
}
// 获取最后一张图片的uid,这个uid是每次上传图片给的唯一值,也是等下用于删除的唯一索引
const uid = this.$refs.upload.uploadFiles.slice(-1)[0].uid;
// 将url和uid唯一索引,全都push到fileList中,保存起来
this.fileList.push({ tempUrl, uid });
},
// 预览图片
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.innerVisible = true;
},
// 删除图片
handleRemove(file) {
// 删除图片主要靠【this.$refs.upload.uploadFiles】
// 无论上传失败还是成功,都会将图片保存在这里,所以我们只需要对他进行操作
// 这是el-upload的一个默认行为
var number = '';
// 遍历上传列表,如果当前需要删除的图片的file.uid和列表中的uid唯一值相等,记住当前的【number 索引】
this.$refs.upload.uploadFiles.forEach((v, i) => {
v.uid == file.uid ? (number = i) : '';
});
// 根据索引,把这个图片剔除出去,这样就能使用默认方法,把图片逻辑剔除
// 但是其实此时图片已经上传到阿里云里了的,我们删除不了阿里云里面的图片,只能在代码层面,进行逻辑删除
this.$refs.upload.uploadFiles.splice(number, 1);
// 同时我们自定义的fileList中,也要把这个图片逻辑删除
this.fileList.splice(number, 1);
},
// 下载图片
handleDownload(file) {
var number = '';
this.$refs.upload.uploadFiles.forEach((v, i) => {
v.uid == file.uid ? (number = i) : '';
});
const tempUrl = this.fileList.slice(number, 1)[0].tempUrl;
// 加上时间戳可以避免阿里云造成的跨域问题
// 为什么可以避免,我也不懂...
axios.get(tempUrl + '?time=' + Date.now(), { responseType: 'blob' }).then((res) => {
const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.href = downloadUrl;
link.download = 'xxx.png';
document.body.appendChild(link);
link.click();
link.remove();
});
},
// 最后我们就获取到了一个所有上传图片集合的数组参数【fileList】,现在只需要将里面的url提取出来,传给后端即可
},
};
</script>