最近做了一个项目,需求是上传文档,文档类型多种,图片,视频,文件,doc,xls,zip,txt 等等,而且文档类型可能是大文件,可能得上百兆,甚至超过1G。
腾讯云文档地址:https://cloud.tencent.com/document/product/436/31953 腾讯云可以支持5G 的文件,还是很厉害的。
这里只要是讲一下使用这个SDK的流程,因为第一次看文档的时候,文档介绍很简洁,甚至有点笼统。我当时都是很懵的,无从下手。
这个是小程序小程序直传实践的实现步骤,同样使用于对象存储。,我们一开始研究SDK对象储存觉得很难,然后想简单点,搞个对象储存,不这么麻烦。最后是借鉴了这里的步骤思路。
1、登录后台创建桶,地域
2、获取秘钥
3、小程序配置白名单
核心代码就这么点,选择文件,将后缀传给服务器,服务器根据后缀,生成一个cos文件路径,计算对应的签名,返回URL和签名信息给前端。
最终效果
wxcs
page{
font-size: 28rpx;
color: #333;
}
.content-row {
display: flex;
height: 48px;
color: #333;
padding-left: 20rpx;
line-height: 48px;
border-bottom: 1rpx solid #ddd;
}
.content-rows {
display: flex;
color: #333;
padding-left: 20rpx;
line-height: 48px;
}
.content-title {
width: 190rpx;
color: #666;
}
.click-btn{
background-color: #E1B368;
}
.click-btn-hover{
background-color: #b98633;
}
/index.wxss/
.title {
display:block;
box-sizing: border-box;
padding: 0 5px;
width: 100%;
height: 30px;
line-height: 30px;
border-top: 1px solid #ccc;
margin:auto;
font-size:14px;
color:#333;
text-align: left;
font-weight: bold;
}
.list-panel{
width: 100%;
}
.sub-title{
display:block;
box-sizing: border-box;
padding: 0 5px;
width: 100%;
height: 30px;
line-height: 30px;
font-size:12px;
color:#333;
text-align: left;
font-weight: bold;
}
.list {
margin-top: 10px;
padding-bottom: 10px;
width: 100%;
}
.button {
font-weight: 500;
float: left;
width: 710rpx;
margin: 0 3px 3px 0;
text-align: center;
font-size: 14px;
height: 60rpx;
padding-top: 6px;
}
.click-btn2 {
background-color: #eee;
}
.click-btn-hover2 {
background-color: #d3d3d3;
}
wxjs
Js部分引入了两个文件,cos-wx-sdk-v5.js 文件可以在github上下载https://github.com/tencentyun/cos-wx-sdk-v5/tree/master/demo
github上右demo吗,我通过demo自己稍微改造了一下。
和config,其中config就是配置的一些内容
var COS = require(‘…/…/lib/cos-wx-sdk-v5’);
const app = getApp()
var config = require(‘…/…/config’)
//这里是获取签名授权
var getAuthorization = function (options, callback) {
wx.request({
method: ‘POST’,
url: config.stsUrl, // 服务端签名,参考 server 目录下的两个签名例子
dataType: ‘json’,
data: {
uid: wx.getStorageSync(‘uid’),
token: wx.getStorageSync(‘token’)
},
header: {
‘content-type’: ‘application/x-www-form-urlencoded’
},
success: function (result) {
var data = result.data.data;
var credentials = data && data.credentials;
// if (!data || !credentials) return console.error(‘credentials invalid’);
console.log(credentials)
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
SecurityToken: credentials.sessionToken,
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
});
},
});
};
var cos = new COS({
getAuthorization: getAuthorization,
});
Page({
/**
- 页面的初始数据
*/
data: {
itemname: ‘’,
id: ‘’,
beizhu: ‘’,
img: [],
pdfFile: ‘’,
fileType: ‘’,
filekeyname: ‘’,
jindu: ‘’,
speed: ‘’,
datalist:[],
realimg:[]
},
onLoad(options) {
if (options.id) {
this.setData({
id: options.id
})
}
},
handleItem(e) {
this.setData({
itemname: e.detail.value
})
},
handlebeizhu(e) {
this.setData({
beizhu: e.detail.value
})
},
//核心代码
postUpload() {
let that = this
wx.chooseMessageFile({
count: 1,
type: ‘all’,
success: function (res) {
let data = res.tempFiles[0]
console.log(data.name)
let testarr = []
testarr.push(data.name.replace(/,/g, ‘’))
that.setData({
realimg:that.data.realimg.concat(testarr)
})
wx.showLoading({
title: ‘上传中…’,
})
var lastDotIndex = data.name.lastIndexOf(“.”); // 查找最后一个"."的索引
var secondPart = data.name.slice(lastDotIndex + 1);
console.log(secondPart)
cos.uploadFile({
Bucket: config.Bucket,
Region: config.Region,
Key: Date.now() + Math.floor(Math.random() * 1000) + ‘.’+secondPart,
FilePath: data.path,
FileSize: data.size,
SliceSize: 1024 * 1024 * 5, // 文件大于5mb自动使用分块上传
onTaskReady: function (taskId) {
TaskId = taskId;
},
onProgress: function (info) {
var percent = parseInt(info.percent * 10000) / 100;
var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100;
console.log(that, ‘进度:’ + percent + ‘%; 速度:’ + speed + ‘Mb/s;’);
that.setData({
jindu: percent,
speed: speed
})
},
onFileFinish: function (err, data, options) {
if(!err){
console.log(that.data.realimg)
let arr = []
arr.push(options.Key)
that.setData({
img: that.data.img.concat(arr) //我们自己稍微改造了一下,上传到腾讯云的文件名是在时间戳+3位的随机数,但是显示在本地的文件名是自己原本给文件的命名。(因为大家的文件命名不规范,长长短短,啥都有。统一命名,在腾讯云后台看起来不会奇奇怪怪。)
})
}else{
that.setData({
realimg:that.data.realimg.pop()
})
}
wx.hideLoading()console.log(options.Key + '上传' + (err ? '失败' : '完成'));},},function (err, data) {console.log(err || data);},);},
});
},
DelImg(e){
console.log(e)
let i = e.currentTarget.dataset.index
let that = this
wx.showModal({
title: ‘提示’,
content: ‘确定要删除吗?’,
cancelText: ‘取消’,
confirmText: ‘确定’,
success: res => {
if (res.confirm) {
that.data.realimg.splice(i, 1);
that.data.img.splice(i, 1);
that.setData({
realimg:that.data.realimg,
img:that.data.img,
})
}
}
})
},
handlesave() {
let that = this
if (!this.data.itemname) {
wx.showToast({
title: ‘请填写文件名称’,
icon: ‘error’,
duration: 2000
})
return
}
if (this.data.realimg.length <1) {
wx.showToast({
title: ‘请上传文件’,
icon: ‘error’,
duration: 2000
})
return
}
wx.showLoading({
title: ‘保存中…’,
})
// console.log(this.data.fileList1)
// var img = [];
// var realimg = [];
// this.data.fileList1.forEach(function (item) {
// var index = 12
// // 分割字符串,取前十位
// var firstPart = item.slice(0, 13);
// // 提取下标12之后的内容
// var index = 12;
// var secondPart = item.slice(index + 1);
// // 提取最后一个"."之后的内容
// var lastDotIndex = item.lastIndexOf(".");
// var thirdPart = item.slice(lastDotIndex + 1);
// img.push(firstPart + "." + thirdPart);
// realimg.push(secondPart);
// });
// console.log(img, realimg)
// return
wx.request({url: app.globalData.siteurlh5 + '/fileadd.php',data: {id: this.data.id,beizhu: this.data.beizhu,uid: wx.getStorageSync('uid'),token: wx.getStorageSync('token'),title: this.data.itemname,img: this.data.img, // 时间戳命名文件realimg: this.data.realimg //文件真实名称},header: {'content-type': 'application/x-www-form-urlencoded'},method: 'POST',success(res) {console.log(res, )if (res.data.bs == 'success') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'success'})setTimeout(() => {wx.navigateBack({delta: 1,})}, 2000);} else if (res.data.bs == 'failed') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'error'})} else if (res.data.bs == 'error') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'error'})} else if (res.data.bs == 'guoqi') {wx.removeStorageSync('userInfo'); //清除缓存wx.removeStorageSync('uid')wx.removeStorageSync('token')wx.redirectTo({url: '../index/index',})}},fail(err) {console.log(err)wx},complete() {// wx.hideLoading()}
})
},
})
上传完成这个文件后缀名就是我们的文件了。但是它不是完整的路径,完整的路径是在腾讯云上面就可以预览了。如果前端要下载文件,那就再让你的后台把完整的路径传回来。
以下是一个简单的上传多种文件类型的方案:
我们最初是指考虑了简单的上传文件,并没有考虑大的文件,所以超过20M 的文件,这里是不支持的。
![在这里插入图片描述](https
😕/img-blog.csdnimg.cn/c1ecbd1f015f43fdb7422f425223ffac.png)
wxml
项目名称:
备注:
*
文件:
<view class="bg-img" wx:for="{{imgList1}}" wx:key="index" style="position: relative;"><image src="{{item}}" mode="aspectFill" data-url="{{item}}" bindtap='previewImage' data-src="{{item}}" style="width:140rpx;height:140rpx;margin: 10rpx 10rpx 10rpx 0 ;"></image><view bindtap="DelImg" data-index="{{index}}"><view style="z-index: 9; margin:10rpx 17rpx 10rpx 0;width: 40rpx;height: 30rpx;background-color: #555;color: white;position: absolute;right: -16rpx;top: -10rpx;text-align: center;line-height: 30rpx;border-radius: 6rpx;">×</view></view></view><view class="bg-img" wx:for="{{videoList1}}" wx:key="index" style="position: relative;"><video src="{{item}}" bindtap="previewVideo" data-url="{{item}}" style="width:140rpx;height:140rpx;margin: 10rpx 10rpx 20rpx 0 ;" autoplay="{{isPlay}}" loop="{{false}}" show-center-play-btn='{{true}}' show-play-btn="{{true}}" controls picture-in-picture-mode="{{['push', 'pop']}}"></video><view bindtap="DelImg2" data-index="{{index}}"><view style="z-index: 9; margin:10rpx 17rpx 10rpx 0;width: 40rpx;height: 30rpx;background-color: #555;color: white;position: absolute;right: -16rpx;top: -10rpx;text-align: center;line-height: 30rpx;border-radius: 6rpx;">×</view></view></view><view class="bg-img" wx:for="{{fileList1}}" wx:key="index" style="position: relative;"><input placeholder="查看附件" class="click-btn2" hover-class="click-btn-hover2" disabled bindtap="handledownload" data-img="{{item}}" placeholder-style="color:#888" name="input" style="padding: 0px 10px;width:640rpx;font-size: 28rpx;color: #888;height: 70rpx;line-height: 70rpx;margin-top: 10rpx;"></input><view bindtap="DelImg3" data-index="{{index}}"><view style="z-index: 9; margin:10rpx 17rpx 10rpx 0;width: 40rpx;height: 30rpx;background-color: #555;color: white;position: absolute;right: -16rpx;top: -10rpx;text-align: center;line-height: 30rpx;border-radius: 6rpx;">×</view></view></view><view bindtap="uploadFileTap" data-id="1" ><view style="width:140rpx;height:140rpx;border:1px dashed #ddd;text-align:center;background:white;position: relative;margin:10rpx 0;"><image src="/images/upload.png" style="width:45rpx;height:37rpx;margin-top: 35rpx;"></image><view style="font-size: 20rpx;color: #333;">文件</view></view></view></view>
</view>
保 存 wxss page{ font-size: 28rpx; color: #333; } .content-row { display: flex; height: 48px; color: #333; padding-left: 20rpx; line-height: 48px; border-bottom: 1rpx solid #ddd; }
.content-rows {
display: flex;
color: #333;
padding-left: 20rpx;
line-height: 48px;
}
.content-title {
width: 190rpx;
color: #666;
}
.click-btn{
background-color: #ff5a28;
}
.click-btn-hover{
background-color: #d44215;
}
/index.wxss/
.title {
display:block;
box-sizing: border-box;
padding: 0 5px;
width: 100%;
height: 30px;
line-height: 30px;
border-top: 1px solid #ccc;
margin:auto;
font-size:14px;
color:#333;
text-align: left;
font-weight: bold;
}
.list-panel{
width: 100%;
}
.sub-title{
display:block;
box-sizing: border-box;
padding: 0 5px;
width: 100%;
height: 30px;
line-height: 30px;
font-size:12px;
color:#333;
text-align: left;
font-weight: bold;
}
.list {
margin-top: 10px;
padding-bottom: 10px;
width: 100%;
}
.button {
float: left;
margin: 0 3px 3px 0;
text-align: left;
font-size: 14px;
height: 28px;
line-height:28px;
padding:0 10px;
}
.click-btn2 {
background-color: #eee;
}
.click-btn-hover2 {
background-color: #d3d3d3;
}
wxjs
const app = getApp()
Page({
/**
- 页面的初始数据
*/
data: {
itemname: ‘’,
id: ‘’,
beizhu: ‘’,
imgList1: [],
fileList1:[],
videoList1:[],
pdfFile: ‘’,
fileType:‘’
},
handledownload(e) {
console.log(e)
let img = e.currentTarget.dataset.img
wx.downloadFile({
url: img,
success: function (res) {
// console.log(res)
// return
var Path = res.tempFilePath //返回的文件临时地址,用于后面打开本地预览所用
wx.openDocument({
filePath: Path,
fileType: Path.split(“.”)[Path.split(“.”).length - 1],
showMenu: true,
success: function (a) {},
fail: function (a) {
console.log(a)
wx.showToast({
title: ‘文件打开失败’,
icon: ‘none’,
duration: 2000,
})
}
})
}
})
},
DelImg(e){
console.log(e)
let i = e.currentTarget.dataset.index
let that = this
wx.showModal({
title: ‘提示’,
content: ‘确定要删除吗?’,
cancelText: ‘取消’,
confirmText: ‘确定’,
success: res => {
if (res.confirm) {
that.data.imgList1.splice(i, 1);
that.setData({
imgList1:that.data.imgList1,
pdfFile:‘’
})
}
}
})
},
DelImg2(e){
console.log(e)
let i = e.currentTarget.dataset.index
let that = this
wx.showModal({
title: ‘提示’,
content: ‘确定要删除吗?’,
cancelText: ‘取消’,
confirmText: ‘确定’,
success: res => {
if (res.confirm) {
that.data.videoList1.splice(i, 1);
that.setData({
videoList1:that.data.videoList1,
pdfFile:‘’
})
}
}
})
},
DelImg3(e){
console.log(e)
let i = e.currentTarget.dataset.index
let that = this
wx.showModal({
title: ‘提示’,
content: ‘确定要删除吗?’,
cancelText: ‘取消’,
confirmText: ‘确定’,
success: res => {
if (res.confirm) {
that.data.fileList1.splice(i, 1);
that.setData({
fileList1:that.data.fileList1,
pdfFile:‘’
})
}
}
})
},
previewImage(e){
console.log(e)
const current = e.currentTarget.dataset.url //获取当前点击的 图片 url
let arr = []
arr.push(current)
wx.previewImage({
current: current,
urls: arr
})
},
previewImg() {
let img = this.pdfFile
wx.downloadFile({
url: img,
success: function(res) {
var Path = res.tempFilePath //返回的文件临时地址,用于后面打开本地预览所用
wx.openDocument({
filePath: Path,
showMenu: true,
success: function(a) {},
fail: function(a) {
wx.showToast({
title: ‘文件打开失败’,
icon: ‘none’,
duration: 2000,
})
}
})
}
})
},
uploadDIY(filePaths, successUp, failUp, i, length) {
wx.showLoading({
title: ‘上传中…’,
})
console.log(filePaths[i])
let that = this
wx.uploadFile({
url: ‘https://www.xxxxx.com/mnp/oaapi/fileupload.php’,
filePath: filePaths[i].path,
name: ‘file’,
formData: {
‘uid’: wx.getStorageSync(‘uid’),
‘token’: wx.getStorageSync(‘token’),
},
success: (res) => {
const data = JSON.parse(res.data.replace(‘\uFEFF’,‘’))
console.log(data)
if (data.bs == ‘success’) {
wx.showToast({
title: data.errmsg,
duration: 2000,
icon: ‘success’
})
successUp++;
// let arr = []
// arr.push(‘https://xxxxx.oss-cn-shenzhen.aliyuncs.com/zhuangshi/zspdf.png’)
let fileType = data.img.split(“.”)[data.img.split(“.”).length - 1]
console.log(fileType,data.img)
if(fileType == ‘pdf’|| fileType == ‘txt’|| fileType == ‘zip’|| fileType == ‘doc’|| fileType == ‘docx’ || fileType == ‘ppt’ || fileType == ‘pptx’ || fileType == ‘xls’ || fileType == ‘xlsx’ ){
that.data.fileList1.push(data.img)
that.setData({
pdfFile:data.img,
fileList1: that.data.fileList1
})
}else if(fileType == ‘jpg’|| fileType == ‘jpeg’ || fileType == ‘png’){
that.data.imgList1.push(data.img)
that.setData({
pdfFile:data.img,
imgList1: that.data.imgList1
})
}else if(fileType == ‘mp4’){
that.data.videoList1.push(data.img)
that.setData({
pdfFile:data.img,
videoList1: that.data.videoList1
})
}
return
that.data.imgList1.push(data.img)
that.setData({
pdfFile:data.img,
imgList1: that.data.imgList1
})
that.data.pdfFile = data.img
// console.log(‘上传图片成功:’, JSON.parse(res.data));
// var data = JSON.parse(res.data);
// console.log(data)
// 把获取到的路径存入imagesurl字符串中
// that.infolist[e].imglist.push(data.img)
// console.log(this.data.imagesurl)
} else if (data.bs == ‘guoqi’) {
wx.showToast({
title: data.errmsg,
duration: 2000,
icon: ‘error’
})
setTimeout(function() {
wx.redirectTo({
url: ‘…/…/pagesD/login/login’
})
}, 500)
} else {
wx.showToast({
title: data.errmsg,
duration: 2000,
icon: ‘error’
})
}
},fail: (res) => {failUp++;},complete: () => {i++;if (i == length) {// Toast('总共' + successUp + '张上传成功,' + failUp + '张上传失败!');} else { //递归调用uploadDIY函数that.uploadDIY(filePaths, successUp, failUp, i, length);}},
});
},
uploadFileTap(e) {
let that = this;
wx.chooseMessageFile({
count: 10,
type: ‘all’,
success(res) {
console.log(res)
// tempFilePath可以作为img标签的src属性显示图片
const tempFilePaths = res.tempFiles
// let fileType = tempFilePaths[0].type
// that.setData({
// fileType:fileType
// })
that.uploadDIY( res.tempFiles, 0, 0, 0, res.tempFiles.length,e);
return
wx.uploadFile({
url: ‘https://www.xxx.com/mnp/oaapi/fileupload.php’,
filePath: tempFilePaths[0].path,
name: ‘file’,
formData: {
‘uid’: wx.getStorageSync(‘uid’),
‘token’: wx.getStorageSync(‘token’),
},
success(res) {
const data = JSON.parse(res.data.replace(‘\uFEFF’,
‘’))
console.log(data)
if (data.bs == ‘success’) {
wx.showToast({
title: data.errmsg,
duration: 2000,
icon: ‘success’
})
let arr = []
arr.push(‘https://xxxxx.oss-cn-shenzhen.aliyuncs.com/zhuangshi/zspdf.png’)
that.setData({
pdfFile:data.img,
imgList1:arr
})
that.data.pdfFile = data.img
} else if (data.bs == 'guoqi') {wx.showToast({title: data.errmsg,duration: 2000,icon: 'error'})setTimeout(function () {// wx.removeStorageSync('userInfo'); //清除缓存// wx.removeStorageSync('uid')// wx.removeStorageSync('token')wx.redirectTo({url: '../index/index',})}, 500)} else {wx.showToast({title: data.errmsg,duration: 2000,icon: 'error'})}}})}
})
},
/**
- 生命周期函数–监听页面加载
*/
onLoad(options) {
// console.log(cos)
if (options.id) {
this.setData({
id: options.id
})
}
},
handleItem(e) {
this.setData({
itemname: e.detail.value
})
},
handlebeizhu(e) {
this.setData({
beizhu: e.detail.value
})
},
handlesave() {
let that = this
if (!this.data.itemname) {
wx.showToast({
title: ‘请填写项目名称’,
icon: ‘error’,
duration: 2000
})
return
}
wx.showLoading({
title: ‘保存中…’,
})
wx.request({url: app.globalData.siteurlh5 + '/fileadd.php',data: {id:this.data.id,beizhu:this.data.beizhu,uid: wx.getStorageSync('uid'),token: wx.getStorageSync('token'),title: this.data.itemname,img: this.data.videoList1.concat(this.data.fileList1, this.data.imgList1)},header: {'content-type': 'application/x-www-form-urlencoded'},method: 'POST',success(res) {console.log(res, )if (res.data.bs == 'success') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'success'})setTimeout(() => {wx.navigateBack({delta: 1,})}, 2000);} else if (res.data.bs == 'failed') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'error'})} else if (res.data.bs == 'error') {wx.showToast({title: res.data.errmsg,duration: 2000,icon: 'error'})} else if (res.data.bs == 'guoqi') {wx.removeStorageSync('userInfo'); //清除缓存wx.removeStorageSync('uid')wx.removeStorageSync('token')wx.redirectTo({url: '../index/index',})}},fail(err) {console.log(err)wx},complete() {// wx.hideLoading()}
})
},
/**
- 用户点击右上角分享
*/
onShareAppMessage() {
}
})