UniApp基于xe-upload实现文件上传组件
xe-upload地址:文件选择、文件上传组件(图片,视频,文件等) - DCloud 插件市场
致敬开发者!!!
感觉好用的话,给xe-upload的作者一个好评
背景:开发中经常会有上传附件的情况,但是找了一圈没有满意的组件,无意间看到xe-upload,满足我需要上传图片和视频的需求,直接使用示例项目开始二次开发my-file-upload。
修改内容:
1.文件的点击事件
2.对video类型文件的处理
3.根据文件名称创建file文件内容
<template><view><view class="upload-wrap"><view class="cu-form-group1"><view class="label">{{label}}:</view><view class="btn-click mgb-16 upload-btn" @click="handleUploadClick" v-show="!disabled"><image :src="icons.upload" mode="aspectFill" class="upload-icon" /><text class="upload-text">上传{{ label }}</text></view></view><view class="mgb-16 file-wrap" v-for="(item, index) in fileList" :key="index"><view class="btn-click file-line" @click="handlePreview(item)"><!-- <view class="btn-click file-line" @click="handleUploadFile(item)"> --><view class="file-info"><image :src="icons[item.fileType || 'file']" mode="aspectFill" class="file-icon" /><text class="file-name">{{ item.name || title[type] }}</text></view><image :src="icons.close" mode="aspectFill" class="file-icon"@click.stop="handleDeleteFile(index)" /></view></view><view class="mgb-16 file-wrap" v-if="fileList.length === 0 && disabled"><view class="file-line"><text class="file-empty">暂无数据</text></view></view><view><video id="myVideo" :src="videoUrl" autoplay loop muted objectFit="cover" v-if="showVideo"></video></view></view><xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload></view>
</template><script>export default {name: 'MyFileUpload',components: {},props: {type: {default: 'image', // image, video, filetype: String,},list: {default: () => ([]),type: Array,},// disabled: {// default: false,// type: Boolean,// },value: {type: String, // 或者是 File[],取决于你的需求default: null},maxFile: {type: Number, //最大上传数量default: 1},label: {type: String, // 或者是 File[],取决于你的需求default: '附件'},},data() {return {// uploadOptions 参数跟uni.uploadFile的参数是一样的(除了类型为Function的属性)uploadOptions: {// url: 'http://192.168.31.185:3000/api/upload', // 不传入上传地址则返回本地链接},uploadUrl: "/sys/common/upload",staticUrl: "/sys/common/static/",fileList: [],title: {image: '图片',video: '视频',file: '文件',},icons: {upload: '/static/xeUpload/icon_upload.png',close: '/static/xeUpload/icon_close.png',image: '/static/xeUpload/icon_image.png',video: '/static/xeUpload/icon_video.png',file: '/static/xeUpload/icon_file.png',},disabled: false,showVideo: false,videoUrl: ''};},watch: {value: {async handler(val) {if (val && val !== null && val !== undefined) {const url = this.$config.apiUrl + this.staticUrl + val;const file = this.urlToFile(url);this.fileList = [file];if (this.fileList.length === this.maxFile) {this.disabled = true;}}},immediate: true,deep: true,},},onLoad: function() {this.videoContext = uni.createVideoContext('myVideo', this)},methods: {handleUploadClick() {// 使用默认配置则不需要传入第二个参数// App、H5 文件拓展名过滤 { extension: ['.doc', '.docx'] } 或者 { extension: '.doc, .docx' }this.$refs.XeUpload.upload(this.type);// 可以根据当前的平台,传入选择文件的参数,例如// 注意 当chooseMedia可用时,会优先使用chooseMedia// // uni.chooseImage// this.$refs.XeUpload.upload(type, {// count: 6,// sizeType: ['original', 'compressed'],// sourceType: ['album'],// });// // uni.chooseVideo// this.$refs.XeUpload.upload(type, {// sourceType: ['camera', 'album'],// });// // uni.chooseMedia (微信小程序2.10.0+;抖音小程序、飞书小程序;京东小程序支持)// this.$refs.XeUpload.upload(type, {// count: 9,// sourceType: ['album', 'camera'],// });},handleUploadCallback(e) {console.log('UploadCallback', e);if (['choose', 'success'].includes(e.type)) {// 根据接口返回修改对应的response相关的逻辑const tmpFiles = (e.data || []).map(({response,tempFilePath,name,fileType}) => {// 当前测试服务返回的数据结构如下// {// "result": {// "fileName": "fileName",// "filePath": `http://192.168.1.121:3000/static/xxxxx.png`,// },// "success": true,// }const res = response?.result || {};const tmpUrl = res.filePath ?? tempFilePath;const tmpName = res.fileName ?? name;return {...res,url: tmpUrl,name: tmpName,fileType,};});this.fileList.push(...tmpFiles);this.handleUploadFile(e.data[0].tempFilePath);}},// 自定义上传handleUploadFile(url) {var that = this;console.log('UploadFile', url);if (url != undefined) {that.$http.upload(that.$config.apiUrl + that.uploadUrl + '?biz=temp', {filePath: url,name: 'file',}).then(res => {console.log('handleUpload success', res);//回传至表单that.$emit('input', res.data.message);const tmpData = JSON.parse(res.data);uni.showToast({title: tmpData.success ? '上传成功' : '上传失败',icon: 'none'});})}},// 预览handlePreview(item) {console.log('PreviewFile', item);const fileType = this.getFileType(item.name);const url = item.url;if (fileType === 'image') {return uni.previewImage({current: url,urls: [url],});}else if (fileType === 'video') {this.videoUrl = url;this.showVideo = !this.showVideo;//全屏显示// this.videoContext.requestFullScreen();}// #ifndef H5else if (fileType === 'office') {return uni.openDocument({filePath: url,fail: (err) => {console.log(err);uni.showToast({icon: 'none',title: '文件预览失败'});},});}// #endifelse{uni.showModal({title: '提示',content: url,showCancel: false,});}},handleDeleteFile(index) {this.fileList.splice(index, 1);if (this.fileList.length < this.maxFile) {this.disabled = false;}},urlToFile(url) {// 获取URL的最后一部分const lastPart = url.split('/').pop();// 获取文件名(不包括扩展名)const filenameWithoutExtension = lastPart.split('_').slice(0, -1).join('_');// 获取文件扩展名const extension = lastPart.split('.').pop();// 组合文件名和扩展名const filename = filenameWithoutExtension + '.' + extension;const fileType = this.getFileType(url);const file = {"fileName": filename,"fileKey": lastPart,"filePath": url,"url": url,"name": filename,"fileType": fileType}return file;},/*** 获取文件类型* @param {String} fileName 文件链接* @returns {String} fileType => '', image, video, audio, office, unknown*/getFileType(fileName = '') {const fileType = fileName.split('.').pop();// let suffix = flieArr[flieArr.length - 1];// if (!suffix) return '';// suffix = suffix.toLocaleLowerCase();const image = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'];if (image.includes(fileType)) return 'image';const video = ['mp4', 'm4v'];if (video.includes(fileType)) return 'video';const audio = ['mp3', 'm4a', 'wav', 'aac'];if (audio.includes(fileType)) return 'audio';const office = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'plain'];if (office.includes(fileType)) return 'office';return 'unknown';},},};
</script><style lang="scss" scoped>view {box-sizing: border-box;}.label{text-align: justify;padding-right: 15px;white-space: nowrap;font-size: 15px;position: relative;height: 30px;line-height: 30px;}.cu-form-group1 {background-color: #ffffff;padding: 1px 15px 1px 0px;display: flex;align-items: center;min-height: 50px;// justify-content: space-between;}.btn-click {transition: all 0.3s;opacity: 1;}.btn-click:active {opacity: 0.5;}.mgb-16 {margin-bottom: 16rpx;&:last-child {margin-bottom: 0;}}.upload-wrap {width: 100%;border-radius: 16rpx;background: white;padding: 32rpx;.upload-btn {width: 60%;height: 120rpx;border: 2rpx dashed #AAAAAA;background: #FAFAFA;border-radius: 16rpx;display: flex;align-items: center;justify-content: center;flex-direction: column;.upload-icon {width: 48rpx;height: 48rpx;margin-bottom: 8rpx;}.upload-text {font-size: 26rpx;color: #9E9E9E;line-height: 40rpx;}}.file-wrap {.file-line {width: 100%;background: #F5F5F5;border-radius: 8rpx;padding: 16rpx;font-size: 26rpx;color: #1A1A1A;line-height: 40rpx;display: flex;align-items: center;justify-content: space-between;.file-info {width: 90%;display: flex;align-items: center;.file-name {max-width: 80%;padding-left: 16rpx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}}.file-icon {width: 40rpx;height: 40rpx;flex-shrink: 0;}.file-empty {color: #999999;}}}}
</style>
父组件中引入使用
<my-file-upload type="file" v-model="model.attachment" label="附件"></my-file-upload>import myFileUpload from '@/components/my-componets/my-file-upload.vue';export default {name: "Test",components:{ myFileUpload },props:{formData:{type:Object,default:()=>{},required:false}},data(){return {model: {},}},onLoad: function (option) {}},created(){},methods:{}}
相关文章:

UniApp基于xe-upload实现文件上传组件
xe-upload地址:文件选择、文件上传组件(图片,视频,文件等) - DCloud 插件市场 致敬开发者!!! 感觉好用的话,给xe-upload的作者一个好评 背景:开发中经常会有…...

以太网交换安全:端口隔离
一、端口隔离 以太交换网络中为了实现报文之间的二层广播域的隔离,用户通常将不同的端口加人不同的 VLAN大型网络中,业务需求种类繁多,只通过 VLAN实现报文的二层隔离,会浪费有限的VLAN资源。而采用端口隔离功能,则可…...

望繁信科技CTO李进峰受邀在上海外国语大学开展流程挖掘专题讲座
2023年,望繁信科技联合创始人兼CTO李进峰博士受邀在上海外国语大学国际工商管理学院(以下简称“上外管院”)开展专题讲座,畅谈流程挖掘的发展及对企业数字化转型的价值。演讲吸引了上外教授和来自各行各业的领军企业学员百余人。 …...

nicegui组件button用法深度解读,源代码IDE运行和调试通过
传奇开心果微博文系列 前言一、button 组件基本用法1. 最基本用法示例2. 创建带图标按钮 二、button按钮组件样式定制1. 按钮的尺寸调整2. 改变颜色示例3. 按钮的自定义字体大小4. 圆角形状示例5. 自定义边框6. 添加阴影7. 复合按钮8. 浮动按钮9. 可扩展浮动操作按钮QFAB10. 按…...
数据结构:树(并查集)
并查集(Union-Find Disjoint Sets 或 Disjoint Set Union,简称DSU)是一种树型的数据结构,主要用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。在并查集中,通常将n个对象划分为不相交的…...

校园二手交易平台的小程序+ssm(lw+演示+源码+运行)
摘 要 随着社会的发展,社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…...
代码随想录训练营第46天|回文子序列
647. 回文子串 class Solution { public:int count0;void check(string& s, int left, int right){while(left>0&&right<s.length()&&s[left]s[right]){count;left--;right;}}int countSubstrings(string s) {for(int i0; i<s.length(); i){chec…...

使用 PowerShell 命令更改 RDP 远程桌面端口(无需修改防火墙设置)
节选自原文:Windows远程桌面一站式指南 | BOBO Blog 原文目录 什么是RDP开启远程桌面 检查系统版本启用远程桌面连接Windows 在Windows电脑上在MAC电脑上在Android或iOS移动设备上主机名连接 自定义电脑名通过主机名远程桌面使用Hosts文件自定义远程主…...
bilibili实现批量发送弹幕功能
代码如下: import random import time import requests from tkinter import *# 弹幕内容列表 # lis_text [ # 京口瓜洲一水间,钟山只隔数重山。,君不见黄河之水天上来,奔流到海不复回。,起舞弄清影,何似在人间! # ] lis_te…...

如何查看上网记录及上网时间?5种按步操作的方法分享!【小白也能学会!】
“知己知彼,百战不殆”,在数字时代,了解自己的上网行为和时长,不仅能帮助我们更好地管理时间,还能提升工作效率和生活质量。 今天,我们就来分享五种简单易懂的方法,即便是网络小白也能轻松学会…...

Nisshinbo日清纺pvs1114太阳模拟器手测
Nisshinbo日清纺pvs1114太阳模拟器手测...
多线程复杂系统调试利器——assert()
调试复杂系统时,最大的难点在于定位问题,如果弄清楚了问题产生的机理,那么就能有针对性的进行解决。 调试复杂系统时,遇到不好定位的问题,就要大胆去猜、去怀疑、去假设,尤其是应该重点怀疑多线程访问&…...
【2024.9.28练习】青蛙的约会
题目描述 题目分析 由于两只青蛙都在跳跃导致变量多,不妨采用物理题中的相对运动思想,设青蛙A不动,青蛙B每次跳米,两只青蛙的距离为米。正常来说,只要模拟青蛙B与青蛙A的相对运动过程,最终当青蛙B与青蛙A距…...

Python入门:类的异步资源管理与回收( __del__ 方法中如何调用异步函数)
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 使用上下文管理器📝 使用 `__del__` 方法📝 结合使用上下文管理器与 `__del__`📝 资源回收的重要性⚓️ 相关链接 ⚓️📖 介绍 📖 在编程中,资源的管理和回收至关重要,尤其是在处理网络请求时。频…...

Android开发中的ViewModel
在Android应用开发中,ViewModel作为架构组件之一,扮演着管理UI数据和生命周期的关键角色。本文将深入探讨ViewModel如何感知View的生命周期,并分析其内核原理,帮助开发者更好地利用ViewModel优化应用架构。 一、ViewModel简介 在…...

Vue 3 文件编译流程详解与 Babel 的使用
文章目录 一、背景二、结论三、vitejs/plugin-vue 插件调试前物料准备vuePlugin 入口buildStart 方法transform 方法 四、vue/compiler-sfc 核心包parse 方法compileScript、rewriteDefault 方法compileTemplate 方法 五、整体架构六、总结参考资料 一、背景 最近正在研究 rea…...
Android常用C++特性之std::chrono
声明:本文内容生成自ChatGPT,目的是为方便大家了解学习作为引用到作者的其他文章中。 std::chrono 是 C11 引入的标准库中的时间处理工具,提供了以多种精度进行时间测量、处理和操作的功能。它允许开发者处理时间点(time_point&am…...
[Oracle] ORA-04036: 实例使用的 PGA 内存超出 PGA_AGGREGATE_LIMIT
有说该问题是因为触发了Oracle的BUG导致,最直接的解决方法就是重启数据库实例; Linux下数据库实例重启...

一次 Spring 扫描 @Component 注解修饰的类坑
问题现象 之前遇到过一个问题,在一个微服务的目录下有相同功能 jar 包的两个不同的版本,其中一个版本里面的类有 Component 注解,另外一个版本的类里面没有 Component 注解,且按照加载的顺序,没有 Component 注解的 j…...

深度学习:调整学习率
目录 前言 一、什么是调整学习率? 二、调整学习率的作用 三、怎么调整学习率 1.有序调整 2.自适应调整 3.自定义调整 4.调整示例 前言 在深度学习中,调整学习率是非常重要的,它对模型的训练效果和收敛速度有显著影响。 一、什么是调整…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...