前言:
Framework7确实是一个不错的框架,接合Cordova写跨平台应用方便快捷,但其中难免会遇到一些问题,比如:如何支持图片上传。
本文涉及的APP用的是七牛的JS-SDK上传图片,生成、获取七牛对象存储的UPTOKEN不在本文讨论范围之内,需要自己参照官方文档。
准备工作:
- 去Cordova项目路径下,先安装两个插件:
# cordova plugin add cordova-plugin-file # cordova plugin add cordova-plugin-image-picker --variable PHOTO_LIBRARY_USAGE_DESCRIPTION="获取权限时的描述信息"
插件项目主页:
https://github.com/wymsee/cordova-imagePicker
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/
- 引入qiniu.min.js文件到Framework7中。
本文涉及的基本思路是:(可有其他方案,会简便很多)
点击屏幕一个a标签后,开启文件选择框(由项目cordova-imagePicker实现),选择文件后,转换,调用七牛的SDK上传文件(含AJAX请求获取UPTOKEN)。
相关主要代码:
// 以上省略 注意,下文中的app指的是 new Framework7()生成的,如果在template文件中,可由methods下定义的任何一个函数,使用 this.$app 获取该对象。
window.imagePicker.getPictures(
function (results) {
for (var i = 0; i < results.length; i++) {
// results[i] 是本地路径,基本格式为: file:///path/fileName.jpg
// key 是用于七牛对象存储的,可以理解为上传以后的文件名
var key = "users/avatar/" + app.utils.id('xxxx-xxxx-xxxx-xxxx') // 此处是用Framework7的utils生成一个ID
var putExtra = {
fname: "", // 原文件名,可为空
params: {}, // 附带参数
mimeType: [] || null // 允许的文件MIME类型(此处为允许所有)
};
var config = {
useCdnDomain: true, // 使用CDN域名
region: qiniu.region.z0 // 存储区域
};
var error = function (err) {
console.log(err); // err是个对象,里面包含三个属性
app.dialog.alert(err.message, function () { })
};
var next = function (res) {
// res里面包括已上传大小(res.total.loaded),总共大小(res.total.total),以及进度(res.total.percent), 详情可参考七牛JS-SDK文档
}
var complete = function (response) {
console.log(response)
}
// 上传Token,为了上传七牛服务器的时候,进行验证使用。
// 由自己服务器根据bucket,accessKey,secretKey等生成。
var uptoken = "xxxxxxxxxxxxxxxx"
// 开始依据本地路径读取文件,之所以这么做,因为如果直接传入results[i]进入qiniu.upload函数的第一个参数,那么最后上传的只是一个本地路径,并非其文件。
// 此步骤的目的是,读取本地文件,并转换传入
window.resolveLocalFileSystemURL(results[i], function (entry) {
entry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function () {
// this.result 是Base64编码的图片文件,开始Base64至Blob对象。
// 此处感谢 https://www.cnblogs.com/jiujiaoyangkang/p/9396043.html 提供思路。
var arr = this.result.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
var blob = new Blob([u8arr], { type: mime });
// 转换完毕,得到blob。
// 开始调用sdk上传接口获得相应的observable,控制上传和暂停。
// 注意:如果此处函数的第一个参数直接传入this.result,那么去七牛后台查看上传数据的话,会是一个base64编码的文件。
observable = qiniu.upload(blob, key, uptoken, putExtra, config);
observable.subscribe({
next: next, // 实时变动
error: error, // 发生错误的时候
complete: complete // 上传完成的时候
})
};
// 以Base64的方式读取
reader.readAsDataURL(file);
})
});
}
}, function (error) {
console.log('Error: ' + error);
app.dialog.alert('Error: ' + error)
}, {
maximumImagesCount: 1, // 每次运行可选择的图片
uality: 50 // 图片质量(最大为100)
}
);
// 以下省略
以上代码中,是从一个函数中截取出来的,这里面有较大的一部分都在做读取文件,并转换成Blob对象(花了我好长时间去找资料并测试)。
如果用input标签获取到的file对象其实并不需要做这类操作,直接传入qiniu.upload函数就好;但在调试过程中,如果直接使用input标签选择文件,iPhone SE模拟器下每次都引起闪退(Android并未尝试)。据查资料得知,可能是因为布局或版本导致,只不过解决方案并不想深究。