uniapp中APP上传文件

uniapp提供了uni.chooseImage(选择图片), uni.chooseVideo(选择视频)这两个api,但是对于打包成APP的话就没有上传文件的api了。因此我采用了plus.android中的方式来打开手机的文件管理从而上传文件。

下面是我封装的APP端选择上传图片,视频,文件的一个上传组件。

<template><view class="upload-container"><u-icon name="plus" @click="showActionSheet" size="23"></u-icon><!-- <view class="upload-list"><view class="upload-item" v-for="(item, index) in fileList" :key="index"><image v-if="item.type === 'image'" class="preview-image" :src="item.url" mode="aspectFill"@click="previewFile(item)"></image><view v-else-if="item.type === 'video'" class="preview-video" @click="previewFile(item)"><image class="video-cover" :src="item.cover || item.url" mode="aspectFill"></image><view class="video-icon"><text class="iconfont icon-play"></text></view></view><view v-else class="preview-file" @click="previewFile(item)"><text class="iconfont icon-file"></text><text class="file-name">{{ item.name }}</text></view><text class="delete-icon" @click.stop="deleteFile(index)">×</text></view><view class="upload-button" v-if="fileList.length < maxCount"@click="showActionSheet"><text class="iconfont icon-add"></text><text class="upload-text">上传{{ getUploadTypeText() }}</text></view></view> --><!-- <view class="upload-tips" v-if="tips">{{ tips }}</view> --></view>
</template><script>
export default {name: 'FileUploader',props: {// 上传文件类型:all-所有类型, image-图片, video-视频, file-文件uploadType: {type: String,default: 'all'},// 标题title: {type: String,default: '文件上传'},// 提示文字tips: {type: String,default: '支持jpg、png、mp4、doc、pdf等格式'},// 最大上传数量maxCount: {type: Number,default: 9},// 初始文件列表value: {type: Array,default: () => []},// 图片类型限制imageType: {type: Array,default: () => ['jpg', 'jpeg', 'png', 'gif']},// 视频类型限制videoType: {type: Array,default: () => ['mp4', 'mov', 'avi']},// 文件类型限制fileType: {type: Array,default: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt']},// 是否上传到服务器uploadToServer: {type: Boolean,default: true},// 上传接口地址uploadUrl: {type: String,default: ''}},data() {return {fileList: [],arrFile:[]}},created() {// 初始化文件列表if (this.value && this.value.length) {this.fileList = JSON.parse(JSON.stringify(this.value))}},watch: {value: {handler(newVal) {if (newVal && newVal.length) {this.fileList = JSON.parse(JSON.stringify(newVal))}},deep: true}},methods: {// 获取上传类型文本getUploadTypeText() {switch (this.uploadType) {case 'image':return '图片'case 'video':return '视频'case 'file':return '文件'default:return '文件'}},// 显示操作菜单showActionSheet() {let itemList = []// if (this.uploadType === 'all' || this.uploadType === 'image') {//   itemList.push('上传图片')// }// if (this.uploadType === 'all' || this.uploadType === 'video') {//   itemList.push('上传视频')// }if (this.uploadType === 'all' || this.uploadType === 'file') {// 检查平台支持// #ifdef APP-PLUSconst appPlus = plus.os.name.toLowerCase();if (appPlus === 'android' || appPlus === 'ios') {itemList.push('上传文件')}// #endif// #ifdef H5itemList.push('上传文件')// #endif// #ifdef MP-WEIXINitemList.push('上传文件')// #endif}uni.showActionSheet({itemList,success: res => {const index = res.tapIndexif (itemList[index] === '上传图片') {this.chooseImage()} else if (itemList[index] === '上传视频') {this.chooseVideo()} else if (itemList[index] === '上传文件') {this.selectAndUploadFile()}}})},// 选择图片chooseImage() {uni.chooseImage({count: this.maxCount - this.fileList.length,sizeType: ['original', 'compressed'],sourceType: ['album', 'camera'],success: res => {const tempFiles = res.tempFiles// 检查文件类型for (let i = 0; i < tempFiles.length; i++) {const file = tempFiles[i]const extension = this.getFileExtension(file.path)if (!this.imageType.includes(extension.toLowerCase())) {uni.showToast({title: `不支持${extension}格式的图片`,icon: 'none'})continue}// 添加到文件列表const fileItem = {name: this.getFileName(file.path),url: file.path,size: file.size,type: 'image',extension: extension,status: 'ready' // ready, uploading, success, fail}this.fileList.push(fileItem)// 上传到服务器if (this.uploadToServer) {this.uploadFileToServer(fileItem, this.fileList.length - 1)}}this.emitChange()}})},// 选择视频chooseVideo() {uni.chooseVideo({count: 1,sourceType: ['album', 'camera'],success: res => {const extension = this.getFileExtension(res.tempFilePath)if (!this.videoType.includes(extension.toLowerCase())) {uni.showToast({title: `不支持${extension}格式的视频`,icon: 'none'})return}// 添加到文件列表const fileItem = {name: this.getFileName(res.tempFilePath),url: res.tempFilePath,cover: '', // 视频封面,可以通过后端生成size: res.size,duration: res.duration,type: 'video',extension: extension,status: 'ready'}this.fileList.push(fileItem)// 上传到服务器if (this.uploadToServer) {this.uploadFileToServer(fileItem, this.fileList.length - 1)}this.emitChange()}})},// 选择并上传文件函数selectAndUploadFile(){// 显示加载提示uni.showLoading({title: '准备选择文件',});// 选择文件this.chooseFile().then(filePath => {// 选择文件成功后上传return this.uploadFile(filePath);}).then(result => {// 上传成功的处理uni.hideLoading();uni.showToast({title: '上传成功',icon: 'success'});console.log('上传结果:', result);// 在此处理上传成功后的业务逻辑}).catch(error => {// 错误处理uni.hideLoading();uni.showToast({title: error.message || '操作失败',icon: 'none'});console.error('文件操作错误:', error);});},// 选择文件方法chooseFile(){return new Promise((resolve, reject) => {try {// #ifdef APP-PLUSconst MediaStore = plus.android.importClass('android.provider.MediaStore');const main = plus.android.runtimeMainActivity();const Uri = plus.android.importClass('android.net.Uri');plus.io.chooseFile({title: '选择文件',filetypes: ['xlsx', 'xls', 'pdf', 'doc', 'docx'], // 允许的文件类型multiple: false, // 是否允许多选}, (event) => {if (event.files && event.files.length > 0) {const tempFilePath = decodeURIComponent(event.files[0]);console.log('选择的虚拟路径:', tempFilePath);// 解析文件IDconst uri = MediaStore.Files.getContentUri("external");// 导入contentResolverplus.android.importClass(main.getContentResolver());// 从虚拟路径中提取IDconst parts = tempFilePath.split(':');const fileId = parts[parts.length - 1];console.log('文件ID:', fileId);// 查询真实路径let cursor = main.getContentResolver().query(uri, ['_data'], "_id=?", [fileId], null);plus.android.importClass(cursor);let realPath = null;if (cursor != null && cursor.moveToFirst()) {const columnIndex = cursor.getColumnIndexOrThrow('_data');realPath = cursor.getString(columnIndex);cursor.close();}if (realPath) {// 转换为file://格式const filePath = 'file://' + realPath;console.log('文件真实路径:', filePath);resolve(filePath);} else {reject(new Error('无法获取文件路径'));}} else {reject(new Error('未选择文件'));}}, (error) => {reject(new Error('选择文件失败: ' + error.message));});// #endif// #ifdef H5// H5环境下的文件选择const input = document.createElement('input');input.type = 'file';input.accept = '.xlsx,.xls,.pdf,.doc,.docx';input.onchange = (e) => {const file = e.target.files[0];if (file) {resolve(file);} else {reject(new Error('未选择文件'));}};input.click();// #endif// #ifdef MP-WEIXIN// 微信小程序环境wx.chooseMessageFile({count: 1,type: 'file',extension: ['xlsx', 'xls', 'pdf', 'doc', 'docx'],success: (res) => {if (res.tempFiles && res.tempFiles.length > 0) {resolve(res.tempFiles[0].path);} else {reject(new Error('未选择文件'));}},fail: (err) => {reject(new Error('选择文件失败: ' + err.errMsg));}});// #endif// 其他平台// #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQreject(new Error('当前平台不支持文件选择'));// #endif} catch (e) {reject(new Error('选择文件出错: ' + e.message));}});},// 上传文件方法uploadFile (filePath){return new Promise((resolve, reject) => {uni.showLoading({title: '上传中...',mask: true});const token = uni.getStorageSync('token');if (!token) {reject(new Error('登录状态已失效,请重新登录'));return;}// 准备表单数据const formData = {// 这里可以添加业务所需参数shangpinbianma: this.goodsDetail?.bianma || '',uploadTime: new Date().getTime()};console.log(filePath,'filepath')uni.uploadFile({url: '...', // 替换为您的服务器地址method: 'POST',name: 'file',filePath: filePath,formData: formData,header: {accept: "application/json",Authorization:"",},success: (res) => {console.log('上传响应:', res);// 检查登录状态if (res.statusCode === 200) {let result;try {// 解析返回结果if (typeof res.data === 'string') {result = JSON.parse(res.data);} else {result = res.data;}// 检查登录状态if (result.code === '-110' || result.code === '-120' || result.code === '-130' || result.code === '-150') {console.log('登录已失效');if (result.code !== '-120') {uni.showToast({title: '登录已失效',icon: 'none'});}// 跳转到登录页uni.reLaunch({url: '/pages/login/index'});reject(new Error('登录已失效'));} else if (result.success) {//此处记得修改成为你的响应判断// 上传成功resolve(result);} else {// 其他业务错误reject(new Error(result.message || '上传失败'));}} catch (e) {reject(new Error('解析上传结果失败: ' + e.message));}} else {reject(new Error('上传请求失败,状态码: ' + res.statusCode));}},fail: (err) => {reject(new Error('上传失败: ' + (err.errMsg || JSON.stringify(err))));},complete: () => {uni.hideLoading();}});});},// 获取文件扩展名getFileExtension(path) {if (!path) return ''return path.substring(path.lastIndexOf('.') + 1) || ''},// 获取文件名getFileName(path) {if (!path) return ''return path.substring(path.lastIndexOf('/') + 1) || '未命名文件'},// 触发变更事件emitChange() {this.$emit('input', this.fileList)this.$emit('change', this.fileList)}}
}
</script><style lang="scss">
.upload-container {width: 100%;padding: 20rpx;box-sizing: border-box;.upload-title {font-size: 30rpx;font-weight: bold;margin-bottom: 20rpx;}.upload-list {display: flex;flex-wrap: wrap;}.upload-item, .upload-button {position: relative;width: 200rpx;height: 200rpx;margin: 0 20rpx 20rpx 0;border-radius: 8rpx;overflow: hidden;box-sizing: border-box;}.upload-item {border: 1rpx solid #eee;.preview-image {width: 100%;height: 100%;}.preview-video {width: 100%;height: 100%;position: relative;.video-cover {width: 100%;height: 100%;}.video-icon {position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);width: 60rpx;height: 60rpx;background-color: rgba(0, 0, 0, 0.5);border-radius: 50%;display: flex;align-items: center;justify-content: center;.icon-play {color: #fff;font-size: 30rpx;}}}.preview-file {width: 100%;height: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;background-color: #f7f7f7;.icon-file {font-size: 60rpx;color: #999;margin-bottom: 10rpx;}.file-name {font-size: 24rpx;color: #666;width: 90%;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}}.delete-icon {position: absolute;right: 0;top: 0;width: 40rpx;height: 40rpx;background-color: rgba(0, 0, 0, 0.5);color: #fff;font-size: 30rpx;display: flex;align-items: center;justify-content: center;z-index: 10;}}.upload-button {border: 1rpx dashed #ddd;display: flex;flex-direction: column;align-items: center;justify-content: center;background-color: #f7f7f7;.icon-add {font-size: 60rpx;color: #999;margin-bottom: 10rpx;}.upload-text {font-size: 24rpx;color: #999;}}.upload-tips {font-size: 24rpx;color: #999;margin-top: 10rpx;}
}
</style>

改组件可以直接调用,希望可以帮助到大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39614.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在vitepress中使用vue组建,然后引入到markdown

在 VitePress 中&#xff0c;每个 Markdown 文件都被编译成 HTML&#xff0c;而且将其作为 Vue 单文件组件处理。这意味着可以在 Markdown 中使用任何 Vue 功能&#xff0c;包括动态模板、使用 Vue 组件或通过添加 <script> 标签为页面的 Vue 组件添加逻辑。 值得注意的…

常见中间件漏洞之一 ----【Tomcat】

中间件Tomcat介绍&#xff1a; tomcat是⼀个开源⽽且免费的jsp服务器&#xff0c;默认端⼝ : 8080&#xff0c;属于轻量级应⽤服务器。它可以实现 JavaWeb程序的装载&#xff0c;是配置JSP&#xff08;Java Server Page&#xff09;和JAVA系统必备的⼀款环境。 在历史上也披露…

Spring Cloud之负载均衡之LoadBalance

目录 负载均衡 问题 步骤 现象 什么是负载均衡&#xff1f; 负载均衡的一些实现 服务端负载均衡 客户端负载均衡 使用Spring Cloud LoadBalance实现负载均衡 负载均衡策略 ​编辑 ​编辑LoadBalancer原理 服务部署 准备环境和数据 服务构建打包 启动服务 上传J…

量化研究--小果聚宽交易系统上线高速服务器,提供源代码

文章链接量化研究--小果聚宽交易系统上线高速服务器&#xff0c;提供源代码https://mp.weixin.qq.com/s/HecSeAvmaCyVCsPhvxA0xg 今天大家反应以前的服务器比较慢&#xff0c;与200多人在使用这个系统&#xff0c;反应比较慢&#xff0c;实时数据请求服务器&#xff0c;服务器还…

蓝桥杯python组备考2(b站课程笔记)超详细

语法进阶 一、列表推导式 想讲解一下示例4到示例7的代码&#xff1a; 4、循环n次生成n个零放进列表中&#xff0c;其实也就是相当于[0]*n&#xff08;列表乘法&#xff0c;将原来的列表循环n次产生一个新的列表&#xff09;&#xff0c;接着在循环n次产生n个这样的列表&#x…

【大模型LLM第十四篇】Agent学习之anthropic-quickstarts Agent

前言 对于anthropic api的快速使用&#xff0c;在github上有几个example Customer Support Agent&#xff1a;由 Claude 提供支持的客户支持代理。该项目演示了如何利用 Claude 的自然语言理解和生成功能来创建可访问知识库的 AI 辅助客户支持系统。Financial Data Analyst &…

用DrissionPage升级网易云音乐爬虫:更稳定高效地获取歌单音乐(附原码)

一、传统爬虫的痛点分析 原代码使用requests re的方案存在以下局限性&#xff1a; 动态内容缺失&#xff1a;无法获取JavaScript渲染后的页面内容 维护成本高&#xff1a;网页结构变化需频繁调整正则表达式 反爬易触发&#xff1a;简单请求头伪造容易被识别 资源消耗大&am…

2025年渗透测试面试题总结- PingCAP安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 PingCAP安全工程师 一、SQL注入判断数据库类型技术分析 1. 常规判断方法 2. 盲注场景下的判断 3. 补…

【加密社】如何创建自己的币圈工具站

需要准备的工作 1.域名 2.服务器 周末的时候主要弄了快讯这方面的代码 我这里用的是星球日报的api&#xff0c;也可以订阅他们的rss&#xff0c;这部分在github上是开源的 https://github.com/ODAILY 我这里用的是WordPressonenav主题&#xff0c;然后用小工具在主页展示&am…

Oracle归档配置及检查

配置归档位置到 USE_DB_RECOVERY_FILE_DEST&#xff0c;并设置存储大小 startup mount; !mkdir /db/archivelog ALTER SYSTEM SET db_recovery_file_dest_size100G SCOPEBOTH; ALTER SYSTEM SET db_recovery_file_dest/db/archivelog SCOPEBOTH; ALTER SYSTEM SET log_archive…

Apache Hive:基于Hadoop的分布式数据仓库

Apache Hive 是一个基于 Apache Hadoop 构建的开源分布式数据仓库系统&#xff0c;支持使用 SQL 执行 PB 级大规模数据分析与查询。 主要功能 Apache Hive 提供的主要功能如下。 HiveServer2 HiveServer2 服务用于支持接收客户端连接和查询请求。 HiveServer2 支持多客户端…

FPGA_DDS_IP核

接下来对FPGA的DDS的ip核进行学习。 首先对DDS需要有些了解 DDS信号发生器采用直接数字频率合成&#xff08;Direct Digital Synthesis&#xff0c;简称DDS&#xff09;技术&#xff0c;简单来说就是 需要一个系统频率和一个输入的数字数据 &#xff0c;用这个系统频率计算出…

欢迎来到未来:探索 Dify 开源大语言模型应用开发平台

欢迎来到未来&#xff1a;探索 Dify 开源大语言模型应用开发平台 如果你对 AI 世界有所耳闻&#xff0c;那么你一定听说过大语言模型&#xff08;LLM&#xff09;。这些智能巨兽能够生成文本、回答问题、甚至编写代码&#xff01;但是&#xff0c;如何将它们变成真正的实用工具…

计算机工具基础(七)——Git

Git 本系列博客为《Missing in CS Class(2020)》课程笔记 Git是一种分布式版本控制系统&#xff0c;被其跟踪的文件可被查询精细到行的修改记录、回退版本、建立分支等 模型 一般流程&#xff1a;工作区 → \to →暂存区 → \to →仓库(本地 → \to →远端) 工作区&#xff1…

uniapp动态循环表单校验失败:初始值校验

问题现象 &#x1f4a5; 在实现动态增减的单价输入表单时&#xff08;基于uv-form组件&#xff09;&#xff0c;遇到以下诡异现象&#xff1a; <uv-input>的v-model绑定初始值为数字类型时&#xff0c;required规则失效 ❌数字类型与字符串类型校验表现不一致 &#x1…

前端框架学习路径与注意事项

学习前端框架是一个系统化的过程&#xff0c;需要结合理论、实践和工具链的综合掌握。以下是学习路径的关键方面和注意事项&#xff1a; 一、学习路径的核心方面 1. 基础概念与核心思想 组件化开发&#xff1a;理解组件的作用&#xff08;复用性、隔离性&#xff09;、组件通信…

【Python机器学习】3.5. 决策树实战:基于Iris数据集

喜欢的话别忘了点赞、收藏加关注哦&#xff08;关注即可查看全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 本文紧承 3.1. 决策树理论(基础) 和 3.2. 决策树理论(进阶)&#xff0c;没看过的建议先看理论分…

Unity2022发布Webgl2微信小游戏部分真机黑屏

复现规律&#xff1a; Unity PlayerSetting中取消勾选ShowSplashScreen 分析&#xff1a; 在Unity中&#xff0c;Splash Screen&#xff08;启动画面&#xff09; 不仅是视觉上的加载动画&#xff0c;还承担了关键的引擎初始化、资源预加载和渲染环境准备等底层逻辑。禁用后导…

docker desktop 集成WSL Ubuntu22.04

Windows docker desktop 设置WSL ubuntu 22.04启用与其他发行版的集成 Windows docker desktop 安装参考 wsl ubuntu 22.04 查看我宿主机的docker desktop 容器全部的信息 wsl -d Ubuntu-22.04 -u root

快速入手-基于Django的主子表间操作mysql(五)

1、如果该表中存在外键&#xff0c;结合实际业务情况&#xff0c;那可以这么写&#xff1a; 2、针对特殊的字典类型&#xff0c;可以这么定义 3、获取元组中的字典值和子表中的value值方法 4、对应的前端页面写法