更新记录
1.0.6(2025-03-30)
修复一处逻辑错误
1.0.5(2025-03-29)
修复全选功能的部分bug
1.0.4(2025-03-29)
修复文件过多导致的组件卡顿问题,每页显示最多500个文件(夹);新增功能,可以全选/全不选文件
查看更多平台兼容性
Vue2 | Vue3 |
---|---|
× | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 4.31,Android:11.0,iOS:不支持,HarmonyNext:不支持 | × | × | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 | 鸿蒙元服务 |
---|---|---|---|---|
× | × | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
× | × | × | × | × | × | × | × | × |
使用前注意
本插件由于使用android.permission.MANAGE_EXTERNAL_STORAGE
权限,因此须确保在Android 11
及以上版本运行。
本插件需要打包自定义调试基座,打包前确保权限已在AndroidManifest.xml
申请,示例如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="io.dcloud.uniappx">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
插件还有任何其他问题,欢迎和作者联系。
使用方法
引入插件
<cfit-filepicker path="/sdcard/DCIM" :multiple="true"></cfit-filepicker>
其中参数path
必须以/sdcard
开头;不写这个参数默认操作目录为/sdcard/Download
。
参数multiple
为true
则文件可多选;否则为单选。
文件选择完成后最终返回的是一个路径数组。
相关事件
import { onInputChange, showFilepick,uploadFile,fileReader } from "@/uni_modules/cfit-filepicker"
onInputChange(callback(e):string) //当有文件被选中后触发,从这里可以接收指定文件的绝对路径的数组,例如["/sdcard/enc.key","/sdcard/.temp","/sdcard/screenshot.png","/sdcard/.archivetemp.zip"]
showFilepick() //引入插件后默认不打开,使用此函数开启文件选择器
uploadFile(uploadurl:string,filepath:string,method:string,data:string,header:string,callback(res,e):string) //filepath为单个文件路径,method为HTTP请求方法(POST、PUT等),data和header为传入的其他HTTP数据,须满足JSON格式;res为返回信息,e为错误信息
fileReader(path:string,method:string,callback(e):string) // path为单个路径,method有base64、hex、raw三种方式,e为回传结果。其中base64返回的为dataURL风格。
参考代码
请注意,以下代码请使用uniapp x
运行。代码内的上传链接、data
、header
等参数运行时须自行修改。
<template>
<view class="container">
<view class="card">
<text class="title">文件上传</text>
<text class="subtitle">选择文件并上传到服务器</text>
<view class="file-picker">
<button class="select-btn" @click="show">
<text class="btn-text">选择文件</text>
</button>
<cfit-filepicker path="/sdcard/DCIM" :multiple="true"></cfit-filepicker>
<view class="file-info" v-if="nowinput">
<text class="file-name">{{nowinput.split('/').pop()}}</text>
<text class="file-selected">已选择文件</text>
</view>
<view class="file-info" v-else>
<text class="file-hint">未选择任何文件</text>
</view>
</view>
<button class="upload-btn" :disabled="nowinput==''" @click="upload">
<text class="btn-text">上传文件</text>
</button>
</view>
</view>
</template>
<script>
import { onInputChange, showFilepick, uploadFile, fileReader } from "@/uni_modules/cfit-filepicker"
export default {
data() {
return {
uploadurl: "http://192.168.43.136:7869/upload",
nowinput: "",
method: "PUT",
data: JSON.stringify({ userId: "123", description: "test file" }) as string,
header: JSON.stringify({ Authorization: "Bearer CF1T70k3n5053" }) as string,
inputarray: [""]
}
},
onLoad() {
// 注册文件选择变化回调,当用户选择文件后会触发
onInputChange((e) => {
console.log(e);
const res = e as string;
this.inputarray = JSON.parse(res) as UTSArray<String>;
this.nowinput = this.inputarray[0]; // 将选择的文件路径保存到nowinput
})
},
methods: {
show() {
// 打开文件选择器
showFilepick();
},
upload() {
if (this.inputarray.length > 0) {
/**
* 这部分为读取文件内容,上传文件不需要
* 使用fileReader可以读取文件内容,支持base64、hex、raw三种格式
**/
// fileReader(this.inputarray[0],"base64",(e)=>{
// console.log(e)
// });
for (var i = 0; i < this.inputarray.length; i++) {
console.log("上传中. . .")
uni.showLoading({
title: `上传${this.inputarray[i]}中. . .`
})
// 调用uploadFile上传文件
// 参数依次为:上传URL、文件路径、HTTP方法、附加数据、请求头、回调函数
uploadFile(
this.uploadurl,
this.inputarray[i],
this.method,
this.data,
this.header,
(result, error) => {
uni.hideLoading();
if (error != "") {
console.log(`Upload failed: ${error}`)
uni.showToast({
title: `上传失败:${error}`,
position: "bottom"
})
} else {
uni.showToast({
title: `上传成功`,
position: "bottom"
})
console.log(`Upload success: ${result.trim()}`)
}
}
)
}
}
}
}
}
</script>
<style>
.container {
display: flex;
justify-content: center;
align-items: center;
background-color: #f5f7fa;
padding: 20px;
}
.card {
width: 100%;
max-width: 500px;
background-color: #ffffff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.title {
font-size: 24px;
font-weight: 700;
color: #333;
text-align: center;
margin-bottom: 8px;
}
.subtitle {
font-size: 14px;
color: #666;
text-align: center;
margin-bottom: 24px;
}
.file-picker {
margin-bottom: 24px;
border: 1px dashed #d9d9d9;
border-radius: 8px;
padding: 20px;
}
.select-btn {
background-color: #409eff;
color: white;
border-radius: 6px;
padding: 1px 5px;
margin-bottom: 16px;
}
.btn-text {
font-size: 16px;
font-weight: 700;
color: #f5f7fa;
}
.file-info {
display: flex;
flex-direction: column;
align-items: center;
}
.file-name {
font-size: 16px;
font-weight: 700;
color: #333;
margin-bottom: 4px;
}
.file-selected {
font-size: 12px;
color: #0077ff;
}
.file-hint {
font-size: 14px;
color: #999;
}
.upload-btn {
background-color: #0066ff;
color: white;
border-radius: 6px;
padding: 7px 5px;
}
</style>