uniapp实现多格式文件上传无论是开发APP、H5、亦或是小程序,我们经常用到图片上传,uniapp官方的组件,插件市
背景
无论是开发APP、H5、亦或是小程序,我们经常用到图片上传,uniapp官方的组件,插件市场上各种上传插件都有。但是支持多种格式或者不限格式的上传组件却寥寥无几。于是我在插件市场上找了个‘yt-upload‘全文件上传插件,分享下它的使用方式。
- 说明:为啥不用uniapp提供的
uni-file-picker
扩展组件呢,因为我开发的是app,而它有多种格式文件上传只支持小程序和H5限制。
介绍
关于为啥用yt-upload
这个插件呢,因为我在插件市场上找到了两个一样的插件,看了下更新时间,这个比较新。
上面这个更完善,但是他的示例代码还复制少了,所以不要用他的示例代码。但是插件装了也能用,估计插件他就是改了个名字,可能更新了里面的一些bug。
开始使用
- 2. 安装完成,项目中多了个模块文件,这样我们就能全局使用该组件了。
- 3. 将组件放到要使用的页面中,包含上传按钮,上传记录文件名显示,点击文件名可预览文件,上传记录删除操作:
<view class="tn-flex">
<view class="tn-flex-1">
<view class="tn-shadow-blur">
<yt-upload ref="uploadFile" childId="upload1" width="150rpx" :option="option" :size="30" :count="3"
:formats="formats" :debug="false" :instantly="true" @uploadEnd="onuploadEnd" @progress="upProgress"
@change="upChange">
<view class="tn-bg-orangered tn-color-white tn-text-center">
选择附件</view>
</yt-upload>
</view>
<view class="tn-shadow-blur" v-for="(item,index) in files.values()" :key="index">
<!-- <image style="width: 100rpx;height: 100rpx;" :src="item.path" mode="widthFix">
</image> -->
<text class="tn-color-blue" @click="look(item.name)">{{item.name}}</text>
<text @click="clear(item.name)" v-if="item.type=='success'"
style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #ff0000;color: #ff0000;">删除</text>
</view>
</view>
</view>
我的页面效果如下,因为我用了图鸟的UI,你们可以自己改下样式:
组件有三个重要的属性,option是定义文件上传接口的相关参数,count是上传文件数量限制,formats是文件上传格式,不写默认全文件格式,写了的话就是逗号隔开,,例如png,jpg,pdf等。下面其他的参数大家可以看下
- 4. data中的配置,files是上传回显记录集合,option则是上传配置,formats是限制允许上传的格式。
option: {
// 上传服务器地址,需要替换为你的接口地址
url: config.baseUrl + '/options/uploadFile', // 该地址非真实路径,需替换为你项目自己的接口地址
// 上传附件的key,后端处理获取文件的字段
name: 'file'
},
formats: '', //限制允许上传的格式,空串=不限制,默认为空,多个格式以逗号隔开,例如png,jpg,pdf
// 文件回显列表
files: new Map(),
-
- 上传时用到的回调函数,
* 某文件上传结束回调(成功失败都回调)
* @param {Object} item 当前上传完成的文件
*/
onuploadEnd(item) {
console.log(`${item.name}已上传结束,上传状态=${item.type}`);
// 更新当前窗口状态变化的文件
this.files.set(item.name, item);
//上传完成后取服务端数据
if (item['responseText']) {
console.log('演示服务器返回的字符串JSON转Object对象', item.responseText);
this.files.get(item.name).responseText = JSON.parse(item.responseText);
//赋值给表单字段
// console.log(this.files.get(item.name).responseText.data.url);
const res_data = this.files.get(item.name).responseText.data
let data = {
name: item.name,
value: res_data.url,
type:res_data.type
}
this.formData.files = this.formData.files.concat([data])
console.log('before delete', this.formData.files);
}
// 强制更新视图
this.$forceUpdate();
// ---可删除--演示判断是否所有文件均已上传成功
let isAll = [...this.files.values()].find(item => item.type !== 'success');
if (!isAll) {
console.log('已全部上传完毕');
} else {
console.log(isAll.name + '待上传');
}
},
upProgress(e) {
console.log('upProgress', e, e.type);
},
upChange(files) {
console.log('当前选择的文件列表:', JSON.stringify([...files.values()]));
// 更新选择的文件
this.files = files;
// 强制更新视图
this.$forceUpdate();
},
/**
* 移除某个文件
* @param {Object} name 带后缀名的文件名称
*/
clear(name) {
// name=指定文件名,不传name默认移除所有文件
this.$refs['uploadFile'].clear(name);
//移除表单里的文件
this.formData.files = this.formData.files.filter(function(item) {
return item.name !== name
});
console.log('after delete', this.formData.files);
},
-
- 服务端处理上传的接口,我用的是PHP开发的:
try {
$tmp_name = $_FILES['file']['tmp_name'];
$file_name = $_FILES['file']['name'];
// var_dump($_FILES);
//初始化变量
$date = date('Ymdhis');
//文件目录
$file_dir = root_path() . 'public/files/' . date('Ymd') . '/';
if (!is_dir($file_dir)) {
mkdir($file_dir);
}
//上传文件路径
$domain = Env::get('app.domain');
//如果当前图片不为空
if (!empty($file_name)) {
$uptype = explode(".", $file_name);
//图片名称
$newname = $date . rand(10000, 99999) . "." . $uptype[count($uptype) - 1];
$uplad_name = $newname;
//如果上传的文件没有在服务器上存在
if (!file_exists($file_dir . $uplad_name)) {
//把图片文件从临时文件夹中转移到我们指定上传的目录中
$file = $file_dir . $uplad_name;
move_uploaded_file($tmp_name, $file);
chmod($file, 0644);
$img_url = $domain . '/files/' . date('Ymd') . '/' . $newname;
if(in_array($uptype[count($uptype) - 1],['jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF'])){
$type = 'image';
}else{
$type = 'file';
}
$data = [
'type'=> $type,
'url'=>$img_url
];
return CatchResponse::success($data, "上传成功");
}
} else {
return CatchResponse::fail('请选择文件上传');
}
} catch (\Exception $e) {
return CatchResponse::fail($e->getMessage());
}
返回值包含了两个参数,文件类型是图片还是文件文档,便于前端预览时使用,如果是图片,则用image标签回显,如果是文件,则用uni.openDocument打开文档,上传成功界面:
点击文件名预览文件代码如下,参数是文件名,根据这个文件名我们可以获取到files集合中的服务端返回值(因为预览图片、问价要用文件网络地址),这样就能看到上传文件内容了。
look(name) {
let data = this.formData.files.filter(function (item) {
return item.name === name
});
console.log(data);
if (data[0].type == 'image') {
this.showImage = true
this.imageUrl = data[0].value
// console.log(this.imageUrl);
return
}
uni.downloadFile({
url: data[0].value, //只能是网络地址
success: function (res) {
var filePath = res.tempFilePath;
uni.openDocument({
filePath: filePath,
showMenu: true,
success(e) {
console.log('success', e);
},
fail(e) {
console.log('fail', e);
}
});
}
})
},
总结
这样的文件上传打破了一些组件的局限性,让我们能够自由地选择适合自己的上传格式,对于我们的开发是很有帮助的。记录一下,下次不用翻以前的代码也会写了呢。
转载自:https://juejin.cn/post/7362821013243166720