项目场景:
uniapp 图片 上传 阿里 OSS 对象存储
需求描述:
H5移动端开发中需要用户上传图片头像、身份证件等需求时。需要将图片上传至阿里oss中存储,并且下载到当前页面进行展示。
解决方案:
代码如下:
需要用到的依赖包:
npm install ali-oss --save
npm install lrz --save
创建一个 upload.js 文件:
const OSS = require("ali-oss"); //引入安装包;
const lrz = require('lrz');
//配置 阿里 oss 存储对应的 bucket 桶
var client = new OSS({
region: "oss-cn-beijing", //指申请OSS服务时的地域
endpoint: "https://oss-cn-beijing.aliyuncs.com", //指定为HTTPS,也可以是IP的形式 region将会被忽略
accessKeyId: "xxxxxxxxxxxxxxxxxx", // 填写你的accessKeyId
accessKeySecret: "xxxxxxxxxxxxxxxxxxxxx", // 填写你的accessKeySecret
bucket: "xxxx", // 桶的名称
secure: true // 配合region使用。如果指定secure为true,则使用HTTPS访问。
});
// 阿里云上传图片
// e : 文件对象,filename:存储文件名,tag:识别当前事件的种类,配合fn使用,imgpath:图片路径,fn:回调函数
export function uploadImg(e, filename, tag, imgpath, fn) {
uni.showLoading({
title: '正在上传...'
});
if (e.tempFiles.length == 0) {
uni.hideLoading();
uni.showToast({
title:'未找到图片',
icon:'none'
})
};
// 检测图片大小
let file = e.tempFiles[0];
if (file.size > 15728640) { // 15M
uni.showToast({
title: "您上传的图片文件过大,请重新上传!",
icon: "none"
});
return false
}
lrz(file, {
width: 500,
}).then(function(res) {
let base64 = res.base64;
let blob = convertBase64UrlToBlob(base64);
let r = Math.random().toString(16).substr(2);
let time = new Date(),
y, m, d;
y = time.getFullYear();
m = String(time.getMonth() + 1).length === 2 ? (time.getMonth() + 1) : "0" + (time.getMonth() + 1);
d = String(time.getDate()).length === 2 ? (time.getDate()) : "0" + time.getDate();
let dfilefold = y + m + d; // 创建时间文件夹
let name;
if (imgpath.indexOf(filename) != -1) {
let tmps = imgpath.split(filename)[1].split('?')[0]; // 获取时间戳
name = filename + tmps;
} else {
name = filename + dfilefold + '/' + r;
}
// 上传图片
client.put(name, blob).then(result => {
// 上传成功 ;
uni.hideLoading();
// 得到图片在oss中的url地址;
let path = result.url;
fn(tag, path);
}).catch(err => {
console.log(err)
uni.showToast({
title: "图上传失败,请重试!",
icon: "none"
})
});
})
}
// 辅助函数
function convertBase64UrlToBlob(urlData) {
var bytes = window.atob(urlData.split(',')[1]); //去掉url的头,并转换为byte
//处理异常,将ascii码小于0的转换为大于0
var ab = new ArrayBuffer(bytes.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {
type: 'image/png'
});
};
在uniapp 项目组件中
<template>
<view>
<view>
<image class="" :src="idImage1" mode="aspectFit" v-if="idImage1"></image>
<text class="" style="font-size: 100rpx;"@tap="uploadImgfn('myImage/', 1, idImage1)" v-else />
</view>
<view>
<image class="" :src="idImage1" mode="aspectFit" v-if="idImage2"></image>
<text class="" style="font-size: 100rpx;"@tap="uploadImgfn('myImage/', 2, idImage2)" v-else />
</view>
......
</view>
</template>
<script>
// 引入方法;
import {uploadImg} from "../../../utils/upload.js";
data() {
return {
idImage1: " ", // 图片1
idImage2:'' '', // 图片2
idImage3:'' '', // 图片3
};
},
methods:{
uploadImgfn(filename, tag, imgpath) {
let that = this;
// 选择图片
uni.chooseImage({
success: (res) => {
console.log(res);
// 调用方法,上传图片
uploadImg(res, filename, tag, imgpath, function(tag, path) {
// 展示上传的图片
if (tag == 1) {
that.idImage1 = path + "?" + Date.now();
} else if (tag == 2) {
that.idImage1 = path + "?" + Date.now();
} else if (tag == 3) {
that.idImage3 = path + "?" + Date.now();
}
})
}
});
},
}
</script>
优化部分
感兴趣的小伙伴可以尝试一下封装成Promise对象,这样就用传递回调函数fn,也不用传递tag参数。在.then()就可以给idImage进行赋值 url
有更好、更加简洁的方法希望大家能给我提出宝贵的意见或链接。