uniapp h5端临时路径转file对象上传

news2024/11/6 14:09:52

文章目录

  • 问题说明
  • 使用说明
    • 1.使用场景
    • 2. 文件需要压缩
    • 3. 使用技术
    • 4. 代码如下
    • 5. utils/index.js 代码
  • 3. 总结说明

问题说明

  1. 只针对uniapp开发H5网页,使用uniapp api获取到的临时路径不能满足使用场景,其他平台未进行测试

使用说明

1.使用场景

使用uview-ui的u-upload组件上传图片

2. 文件需要压缩

我的业务场景是上传图片之后,需要使用ocr识别,文件太大的话,识别比较缓慢,所以需要进行压缩

3. 使用技术

// npm install compressorjs
import Compressor from 'compressorjs';

4. 代码如下

这是在u-upload组件的基础上进行封装的ImageUpload组件, 先获取到临时路径,通过fetch请求获取到blob对象,然后再进行转file处理,相应的处理函数是tempFilePathToFile,compressFile

<template>
    <view class="upload-container">
        <u-upload :previewImage="true" :max-count="maxCount" :auto-upload="false" @afterRead="handleAfterRead"
            @beforeRead="handleBeforeRead" :useBeforeRead="true" @delete="handleDelete" :multiple="multiple"
            :accept="accept" :fileList="fileList">
            <slot name="file"></slot>
        </u-upload>
    </view>
</template>

<script>
import { getToken, tempFilePathToFile, compressFile } from "@/utils";
import { uploadFile } from "@/utils/api";

export default {
    data() {
        return {
            fileList: [
                // {
                //     url: "/dev-api/profile/upload/2024/10/30/公司logo_20241030231031A009.jpg",
                // },
            ],
        };
    },
    props: {
        value: [String, Object, Array],
        maxCount: {
            type: Number,
            default: 1,
        },
        // 文件大小限制 M
        fileSize: {
            type: Number,
            default: 20,
        },
        fileType: {
            type: Array,
            default: () => ["jpg", "png", "jpeg"],
        },
        accept: {
            type: String,
            default: "image",
        },
        multiple: {
            type: Boolean,
            default: false,
        },
        //  是否压缩的阈值 单位M
        threshold: {
            type: Number,
            default: 1,
        },
    },
    watch: {
        value: {
            handler(val) {
                if (val) {
                    // 首先将值转为数组
                    const list = Array.isArray(val)
                        ? val
                        : this.value.split(",");
                    // 然后将数组转为对象数组
                    this.fileList = list.map((item) => {
                        if (typeof item === "string") {
                            let baseURL = this.globalVar.request.baseURL;
                            if (item.indexOf(baseURL) === -1) {
                                item = {
                                    name: baseURL + item,
                                    url: baseURL + item,
                                };
                            } else {
                                item = { name: item, url: item };
                            }
                        }
                        return item;
                    });
                } else {
                    this.fileList = [];
                    return [];
                }
            },
            deep: true,
            immediate: true,
        },
    },
    methods: {
        // uploadFilePromise(url) {
        //     return new Promise((resolve, reject) => {
        //         uni.uploadFile({
        //             url: `${this.globalVar.request.baseURL}/common/upload`, // 仅为示例,非真实的接口地址
        //             filePath: url,
        //             name: "file",
        //             header: {
        //                 Authorization: "Bearer " + getToken(),
        //             },
        //             success: (res) => {
        //                 setTimeout(() => {
        //                     resolve(JSON.parse(res.data));
        //                 }, 1000);
        //             },
        //         });
        //     });
        // },
        uploadFilePromise(file) {
            return new Promise(async (resolve, reject) => {
                try {
                    let formData = new FormData();
                    formData.append("file", file, file.name);
                    fetch(`${this.globalVar.request.baseURL}/common/upload`, {
                        method: "POST",
                        headers: {
                            Authorization: "Bearer " + getToken(),
                        },
                        body: formData,
                    })
                        .then((res) => res.json())
                        .then((res) => {
                            resolve(res);
                        });
                } catch (error) {
                    console.log(error);
                    resolve(null);
                }
            });
        },

        handleBeforeRead(e) {
            let files = typeof e.file === "object" ? [e.file] : e.file;
            let isLimitSize = files.some(
                (file) => file.size > this.fileSize * 1024 * 1024
            );
            if (isLimitSize) {
                this.$u.toast(`文件大小不能超过${this.fileSize}MB`);
                return false;
            }
            let isLimitType = files.some(
                (file) => !this.fileType.includes(file.name.split(".").pop())
            );
            if (isLimitType) {
                this.$u.toast(`仅支持${this.fileType.join(",")}格式`);
                return false;
            }
            return true;
        },

        async handleAfterRead(e) {
            let files = typeof e.file === "object" ? [e.file] : e.file;
            files.map((item) => {
                this.fileList.push({
                    ...item,
                    status: "uploading",
                    message: "上传中",
                });
            });
            let start = 0;
            for (let i = 0; i < files.length; i++) {
                let item = files[i];
                let file = await tempFilePathToFile({
                    tempFilePath: item.url,
                    fileName: item.name,
                });
                // 判断是否需要压缩
                if (file.size > this.threshold * 1024 * 1024) {
                    file = await compressFile(file, { quality: 0.2 });
                }
                let res = await this.uploadFilePromise(file);
                if (res.code == 200) {
                    this.fileList.splice(
                        start,
                        1,
                        Object.assign(item, {
                            status: "success",
                            message: "",
                            url: this.globalVar.request.baseURL + res.fileName,
                        })
                    );
                } else {
                    this.fileList.splice(
                        start,
                        1,
                        Object.assign(item, {
                            status: "error",
                            message: "上传失败",
                        })
                    );
                }
                start++;
            }
            this.$emit("input", this.listToString(this.fileList));
            let list = this.fileList.map((item) => {
                item.url = item.url.replace(this.globalVar.request.baseURL, "");
                return item;
            });
            this.$emit("change", list);
        },
        handleDelete(e) {
            this[`fileList`].splice(e.index, 1);
            this.$emit("input", this.listToString(this.fileList));
            // this.$emit("change", this.fileList);
        },
        // 对象转成指定字符串分隔
        listToString(list, separator) {
            let strs = "";
            separator = separator || ",";
            for (let i in list) {
                if (list[i].url) {
                    strs +=
                        list[i].url.replace(
                            this.globalVar.request.baseURL,
                            ""
                        ) + separator;
                }
            }
            return strs != "" ? strs.substr(0, strs.length - 1) : "";
        },
    },
};
</script>

<style scoped>
.upload-container {
    padding: 20px;
}

.upload-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px dashed #d9d9d9;
    border-radius: 5px;
    padding: 20px;
    cursor: pointer;
}

.upload-file {
    position: relative;
    margin-top: 10px;
}

.upload-file image {
    border: 1px solid #d9d9d9;
    border-radius: 5px;
}

.upload-file .u-icon {
    position: absolute;
    top: 5px;
    right: 5px;
}
</style>

5. utils/index.js 代码

import Compressor from 'compressorjs';

export const getToken = () => uni.getStorageSync('token') || '';

export const removeToken = () => uni.removeStorageSync('token');

export const base64Encode = (str) => {
    // 将字符串转换为 UTF-8 编码的字节数组
    const utf8Bytes = new TextEncoder().encode(str);
    // 将字节数组转换为 Base64 字符串
    return btoa(String.fromCharCode.apply(null, utf8Bytes));
};

export const base64Decode = (base64) => {
    // 将 Base64 字符串转换为字节数组
    const byteString = atob(base64);
    // 将字节数组转换为 UTF-8 字符串
    const bytes = new Uint8Array(byteString.length);
    for (let i = 0; i < byteString.length; i++) {
        bytes[i] = byteString.charCodeAt(i);
    }
    return new TextDecoder().decode(bytes);
};

export const goPageByPath = (path, query = {}) => {
    if (!path) {
        throw new Error('缺少必须的path参数');
    }
    let queryLen = Object.keys(query).length;
    let queryStr = '';
    if (queryLen) {
        queryStr = Object.keys(query)
            .map((key) => `${key}=${query[key]}`)
            .join('&');
        queryStr = `?${queryStr}`;
    }
    uni.navigateTo({url: `${path}${queryStr}`});
};

// 表单重置
export function resetForm(refName) {
    if (this.$refs[refName]) {
        this.$refs[refName].resetFields();
    }
}

// 判断 是否是数字
export const isStrictNumber = (value) => {
    return typeof value === 'number' && !isNaN(value);
};

// 获取文件的后缀名,不包含 .
export const getFileExt = (fileName) => {
    return fileName.split('.').pop();
};

// 临时路径转file对象 针对h5端
export const tempFilePathToFile = ({tempFilePath, fileName}) => {
    if (!tempFilePath) {
        return Promise.resolve(null);
    }
    return new Promise(async (resolve, reject) => {
        try {
            const response = await fetch(tempFilePath);
            const blob = await response.blob();
            const mimeType = response.headers.get('content-type');
            const file = new File([blob], fileName, {type: mimeType});
            resolve(file);
        } catch (error) {
            resolve(null);
        }
    });
};

// 压缩文件
export const compressFile = (file, options) => {
    return new Promise((resolve, reject) => {
        new Compressor(file, {
            ...options,
            success(result) {
                resolve(result);
            },
            error(err) {
                reject(err);
            },
        });
    });
};

3. 总结说明

可能有更好的处理方式, 如果大家有更好的处理方式,可以在评论区,贴出代码,让播主也学习一下,学无止境

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙5.0时代:原生鸿蒙应用市场引领开发者服务新篇章

前言 10月22日原生鸿蒙之夜发布会宣布HarmonyOS NEXT正式发布&#xff0c;首个版本号&#xff1a;鸿蒙5.0。这次“纯血鸿蒙”脱离了底层安卓架构成为纯国产的独立系统&#xff0c;仅凭这一点就有很多想象空间。 目前鸿蒙生态设备已超10亿&#xff0c;原生鸿蒙操作系统在中国市…

Spark的容错机制

1&#xff0c;Spark如何保障数据的安全 1、RDD容错机制&#xff1a;persist持久化机制 1&#xff09;cache算子 - 功能&#xff1a;将RDD缓存在内存中 - 语法&#xff1a;cache() - 本质&#xff1a;底层调用的还是persist&#xff08;StorageLevel.MEMORY_ONLY&#xff09;&…

Web3对社交媒体的影响:重新定义用户互动方式

随着互联网的发展和人们对隐私、安全、所有权的需求不断提高&#xff0c;Web3 的概念逐渐深入人心。Web3 的出现标志着一个去中心化、用户主导的网络时代的到来&#xff0c;这也将对社交媒体产生深远的影响。Web3 不仅推动社交媒体从中心化模式向用户主导的去中心化模式转变&am…

高通Quick板上安装编译Ros1 noetic,LeGO_LOAM,FAR_Planner和rslidar_sdk

环境要求&#xff1a; 这里quick板上安装的是Ubuntu20.04版本 Ros Noeti安装&#xff1a; 1.设置软件源&#xff1a; 官方提供的软件源&#xff1a; sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.…

解决Knife4j 接口界面UI中文乱码问题

1、查看乱码情况 2、修改 编码设置 3、删除 target 文件 项目重新启动 被坑死了

HTML 标签属性——<a>、<img>、<form>、<input>、<table> 标签属性详解

文章目录 1. `<a>`元素属性hreftargetname2. `<img>`元素属性srcaltwidth 和 height3. `<form>`元素属性actionmethodenctype4. `<input>`元素属性typevaluenamereadonly5. `<table>`元素属性cellpaddingcellspacing小结HTML元素除了可以使用全局…

仿真APP助力汽车零部件厂商打造核心竞争力

汽车零部件是汽车工业的基石&#xff0c;是构成车辆的基础元素。一辆汽车通常由上万件零部件组成&#xff0c;包括发动机系统、传动系统、制动系统、电子控制系统等&#xff0c;它们共同确保了汽车的安全、可靠性及高效运行。 在汽车产业快速发展的今天&#xff0c;汽车零部件…

.NET周刊【11月第1期 2024-11-03】

国内文章 .NET 9 AOT的突破 - 支持老旧Win7与XP环境 https://www.cnblogs.com/lsq6/p/18519287 .NET 9 引入了 AOT 支持&#xff0c;使得应用程序能够在编译时优化&#xff0c;以在老旧 Windows 系统上运行。这项技术通过静态编译&#xff0c;消除运行时的 JIT 编译&#xf…

江协科技STM32学习- P36 SPI通信外设

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

Type-C接口 PD 受电端(sink)快充协议芯片,XSP08Q应用小家电领域的方案

前言 在智能家居浪潮的推动下&#xff0c;小家电作为日常生活中不可或缺的一部分&#xff0c;其供电方式的创新与优化正逐步成为行业关注的焦点。随着快充技术的普及&#xff0c;特别是Power Delivery&#xff08;PD&#xff09;协议的广泛应用&#xff0c;一种新型供电模式—…

Memento 备忘录模式

备忘录模式 意图结构适用性实例Java Web开发中的简单示例Originator 类Memento 类Caretaker 类 文本编辑器示例1. Originator (发起人) - TextEditor2. Memento (备忘录) - TextMemento3. Caretaker (负责人) - History4. 使用示例输出 备忘录模式&#xff08;Memento Pattern&…

网络应用技术 实验二:交换机VLAN 应用(华为ensp)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验任务及要求 1、任务 1&#xff1a;在交换机上创建VLAN 并测试通信 2、任务 2&#xff1a;路由交换机实现VLAN 之间通信 六、实验步骤 1、完成任务 1 2、完成任务 2 一、实验简介 在交换机上配置 VLAN&#x…

大模型应用:新时代的多模态交互

引言 如果把大模型接入到终端设备&#xff0c;会怎么样&#xff1f; &#xff08;1&#xff09;智能交互回顾 历史文章《[智能交互复兴&#xff1a;ChatGPT 终端&#xff08;奔驰/Siri&#xff09; &#xff1f;]》中提到&#xff1a;大模型遍布多个应用场景 其中有智能对话…

一周内从0到1开发一款 AR眼镜 相机应用?

目录 1. &#x1f4c2; 前言 2. &#x1f4a0; 任务拆分 2.1 产品需求拆分 2.2 开发工作拆分 3. &#x1f531; 开发实现 3.1 代码目录截图 3.2 app 模块 3.3 middleware 模块 3.4 portal 模块 4. ⚛️ 拍照与录像 4.1 前滑后滑统一处理 4.2 初始化 View 以及 Came…

信息安全工程师(76)网络安全应急响应技术原理与应用

前言 网络安全应急响应&#xff08;Network Security Incident Response&#xff09;是针对潜在或已发生的网络安全事件而采取的网络安全措施&#xff0c;旨在降低网络安全事件所造成的损失并迅速恢复受影响的系统和服务。 一、网络安全应急响应概述 定义&#xff1a;网络安全应…

用图说明 CPU、MCU、MPU、SoC 的区别

CPU CPU 负责执行构成计算机程序的指令&#xff0c;执行这些指令所指定的算术、逻辑、控制和输入/输出&#xff08;I/O&#xff09;操作。 MCU (microcontroller unit) 不同的 MCU 架构如下&#xff0c;注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…

vue3动态监听div高度案例

案例场景 场景描述&#xff1a;现在左边的线条长度需要根据右边盒子的高度进行动态变化 实践代码案例 HTML部分 <div v-for"(device, index) in devices" :key"index"><!-- 动态设置 .left-bar 的高度 --><div class"left-bar"…

【Docker系列】指定系统平台拉取 openjdk:8 镜像

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【含文档+源码】基于SpringBoot+Vue的新型吃住玩一体化旅游管理系统的设计与实现

开题报告 本文旨在探讨新型吃住玩一体化旅游管理系统的设计与实现。该系统融合了用户注册与登录、旅游景点管理、旅游攻略发帖、特色旅游路线推荐、附近美食推荐以及酒店客房推荐与预定等多项功能&#xff0c;旨在为游客提供全方位、一体化的旅游服务体验。在系统设计中&#…

B3735 [信息与未来 2018] 圣诞树

题目描述 圣诞树共有 nn 层&#xff0c;从上向下数第 11 层有 11 个星星、第 22 层有 22 个星星、以此类推&#xff0c;排列成下图所示的形状。 星星和星星之间用绳子连接。第 1,2,\cdots, n - 11,2,⋯,n−1 层的每个星星都向下一层最近的两个星星连一段绳子&#xff0c;最后一…