背景
之前写过一篇【uniapp多格式文件选择(APP,H5)】文章使用renderjs来实现H5端和APP端选择文件,当时文章中只涉及了如何选择文件,今天的文章作为补充来实现怎么将选择好的文件进行上传。
实现思路
上次我们能获取到blob格式的文件流,在H5端这个blob流可以直接通过uni.uploadFile相关的API进行上传,这种方案本来就是使用html端的dom实现,所以并无问题。但是在APP端的blob流上传则会报错。这里我们的思路是再renderjs视图层通过FileReader将文件转成base64,然后把选择的文件base64数据发送到逻辑层,逻辑层将base64转成一个path,这样就可以正式上传。
代码实现
思路上面已经有了,这里就直接上代码:
<template>
<view class="content">
<button @click="fileChoose">文件选择</button>
<view :fileData="fileData" :change:fileData="renderJS.receiveFileData"/>
<view style="word-break:break-all;">文件路径:{{filePath}}</view>
</view>
</template>
<script>
export default {
data() {
return {
fileData: '',
filePath: '',
fileName: ''
}
},
onLoad() {
},
methods: {
fileChoose(){
this.fileData = 'test'
setTimeout(()=> {
this.fileData = ''
},1000)
},
async receiveRenderFile(result){
// #ifdef APP-PLUS
const fileUrl = await this.base64toPath(result.filePath, result.name);
this.fileName = fileUrl.relativePath
this.filePath = fileUrl.localAbsolutePath
// #endif
// #ifdef H5
this.fileName = result.name
this.filePath = result.filePath
// #endif
console.log('选择文件的路径:'+this.filePath)
},
//将base64转成路径
async base64toPath(base64, attachName) {
console.log('base64开始转化成文件')
let _that = this;
return new Promise(function(resolve, reject) {
const filePath = `_doc/yourFilePath/${attachName}`;
plus.io.resolveLocalFileSystemURL('_doc', function(entry) {
entry.getDirectory("yourFilePath", {
create: true,
exclusive: false,
}, function(entry) {
entry.getFile(attachName, {
create: true,
exclusive: false,
}, function(entry) {
entry.createWriter(function(writer) {
writer.onwrite = function(res) {
console.log('base64转化文件完成')
const obj = {
relativePath: filePath,
localAbsolutePath: plus.io
.convertLocalFileSystemURL(
filePath)
}
resolve(obj);
}
writer.onerror = reject;
writer.seek(0);
writer.writeAsBinary(_that
.getSymbolAfterString(base64,
','));
}, reject)
}, reject)
}, reject)
}, reject)
})
},
// 取某个符号后面的字符
getSymbolAfterString(val, symbolStr) {
if (val == undefined || val == null || val == "") {
return "";
}
val = val.toString();
const index = val.indexOf(symbolStr);
if (index != -1) {
val = val.substring(index + 1, val.length);
return val;
} else {
return val
}
}
}
}
</script>
<script module="renderJS" lang="renderjs">
export default {
data() {
return {}
},
mounted() {
console.log('mounted')
},
methods: {
receiveFileData(newValue, oldValue, ownerVm, vm){
if(!newValue){
return
}
this.createFileInputDom(ownerVm)
},
createFileInputDom(ownerVm){
let fileInput = document.createElement('input')
fileInput.setAttribute('type','file')
fileInput.setAttribute('accept','*')
fileInput.click()
fileInput.addEventListener('change', e => {
let file = e.target.files[0]
// #ifdef APP-PLUS
console.log('开始读取文件')
let reader = new FileReader();
//读取图像文件 result 为 DataURL, DataURL 可直接 赋值给 img.src
reader.readAsDataURL(file);
reader.onload = function(event) {
const base64Str = event.target.result; // 文件的base64
console.log('文件读取完成')
//如果文件较大,这里调用到逻辑层可能时间较长
ownerVm.callMethod('receiveRenderFile', {
name: file.name,
filePath: base64Str
})
}
// #endif
// #ifdef H5
const filePath = URL.createObjectURL(file)
ownerVm.callMethod('receiveRenderFile',{
name: file.name,
filePath: filePath
})
// #endif
})
}
}
}
</script>
<style>
</style>
运行结果
我们这里选择手机一个txt文件
查看打印日志
界面上选择结果
到这里拿到文件路径之后就可以上传了。
注意事项
这种方式因为要进行逻辑层和视图层通讯,在APP侧如果选择大文件可能会造成内存溢出或者等待时间过长的问题,请自行取舍。
尾巴
今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!