【Vue2】Vant2上传文件使用formData方式,base64图片转Blob再转File上传

文章详细介绍了如何在Vue项目中,利用vant2的uploader组件结合base64ToBlob工具函数,将base64格式的图片转换为Blob对象,进一步转换为File对象,并通过formData进行上传。过程中涉及到了axios的使用,以及上传过程中的错误处理和文件名、mime类型的获取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

vant2上传组件传送门
使用vant2组件中的uploader组件

<van-uploader v-model="fileList" multiple capture :after-read="afterRead" @delete="onDelete" />

提示:以下是本篇文章正文内容,下面案例可供参考

一、base64转换为 Blob 对象的方法

在utils文件夹下,创建一个工具类js,名叫base64toFile.js

// 转换为 Blob 对象的方法 (可复用)
export function base64ToBlob(base64Data) {
    const parts = base64Data.split(";base64,");
    const contentType = parts[0].split(":")[1];
    const raw = window.atob(parts[1]);
    const rawLength = raw.length;
    const uInt8Array = new Uint8Array(rawLength);
    for (let i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }
    return new Blob([uInt8Array], { type: contentType });
}
// 从 base64 数据中获取文件名和 mime 类型的方法 (可复用)
export function getFilenameAndMimetypeFromBase64(base64Data) {
    const fileInfo = base64Data.split(';base64,')[0].substring(5).split(':');
    const mimeType = fileInfo[0];
    const filename = fileInfo[1];
    return [filename, mimeType];
}
/**
 *  用法
// 将 base64 编码的文件数据转为 Blob 对象
const blob = base64ToBlob(res);
// 获取文件名和 mime 类型
const [filename, mimeType] = getFilenameAndMimetypeFromBase64(res);
// 将 Blob 对象转换为 File 对象
const file = new File([blob], filename, { type: mimeType });
// 上传文件
const formData = new FormData();
formData.append('file', file);

axios.post('/api/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  }
}).then(response => {
  console.log(response.data);
}).catch(error => {
  console.log(error);
});
 */

用法在上面代码里有,也就是后面的过程

二、使用步骤

1.引入工具类js

代码如下(示例):

import {
    base64ToBlob,
    getFilenameAndMimetypeFromBase64
} from "@/utils/base64toFile.js"

2.编写formData上传方法

src/api里面的某一个文件夹里面编写你的上传
在这里插入图片描述

代码如下(示例):

import request from '@/utils/request'
// 上传图片
export function uploadImg(data) {
    return request({
        url: '/flow/common/upload',
        method: 'post',
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        data: data
    })
}

根据实际情况修改url地址,

3.api方法中的request代码

在utils工具文件夹中新建request.js

import axios from 'axios'
import errorCode from '@/utils/errorCode'
import {
	getToken
} from '@/utils/auth'
import {
	Dialog,
	Notify
} from 'vant';
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'

// 创建axios实例
const service = axios.create({
	// axios中请求配置有baseURL选项,表示请求URL公共部分
	// baseURL: '/',
	baseURL: process.env.VUE_APP_BASE_API,
	// 超时
	timeout: 40000
})
// request拦截器
service.interceptors.request.use(config => {
	// 是否需要设置 token
	const isToken = (config.headers || {}).isToken === false
	// config.headers['Authorization'] = sessionStorage.getItem('token') // 让每个请求携带自定义token 请根据实际情况自行修改
	// config.headers['token'] = sessionStorage.getItem('token') // 让每个请求携带自定义token 请根据实际情况自行修改
	config.headers['Authorization'] = 'Bearer ' + getToken()
	// get请求映射params参数
	if (config.method === 'get' && config.params) {
		let url = config.url + '?';
		for (const propName of Object.keys(config.params)) {
			const value = config.params[propName];
			var part = encodeURIComponent(propName) + "=";
			if (value !== null && typeof (value) !== "undefined") {
				if (typeof value === 'object') {
					for (const key of Object.keys(value)) {
						let params = propName + '[' + key + ']';
						var subPart = encodeURIComponent(params) + "=";
						url += subPart + encodeURIComponent(value[key]) + "&";
					}
				} else {
					url += part + encodeURIComponent(value) + "&";
				}
			}
		}
		url = url.slice(0, -1);
		config.params = {};
		config.url = url;
	}
	return config
}, error => {
	console.log(error)
	Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
	// 未设置状态码则默认成功状态
	const code = res.data.code || 200;
	// 获取错误信息
	const msg = errorCode[code] || res.data.msg || errorCode['default']
	// 二进制数据则直接返回
	if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
		return res.data
	}
	if (code === 401) {
		return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
	} else if (code === 402) {
		Dialog.alert({
			message: res.data.msg,
			confirmButtonColor: "#3478F3",
		}).then(() => {

		});
		return Promise.reject(new Error(msg))
	} else if (code === 403) {
		return Promise.reject(new Error(msg))
	} else if (code === 500) {
		Notify({
			type: 'danger',
			message: msg
		});
		return Promise.reject(new Error(msg))
	} else if (code === 601) {
		Notify({
			type: 'warning',
			message: msg
		});
		return Promise.reject('error')
	} else if (code !== 200) {
		Dialog({
			title: '错误',
			message: msg
		});
		return Promise.reject('error')
	} else {
		return res.data
	}
},
	error => {
		console.log('err' + error)
		let {
			message
		} = error;
		if (message == "Network Error") {
			message = "后端接口连接异常";
		} else if (message.includes("timeout")) {
			message = "系统接口请求超时";
		} else if (message.includes("Request failed with status code")) {
			message = "系统接口" + message.substr(message.length - 3) + "异常";
		}
		Notify({
			message: message,
			type: 'danger',
			duration: 5 * 1000,
		});
		return Promise.reject(error)
	}
)
export default service

request.js有许多的工具类引入,不过一般的vue项目应该都有脚手架,如果没有的,或者没见过这个request.js的,可以去翻一下若依后台管理系统的源码。这里只作示例,告知请求方法中的封装是这些代码


三、实际操作

1.html代码

<van-uploader v-model="fileList" multiple capture :after-read="afterRead" @delete="onDelete" />

2.js代码

import方法

import {
    base64ToBlob,
    getFilenameAndMimetypeFromBase64
} from "@/utils/base64.js"
import {
    uploadImg, // 上传拍照的图片
} from "@/api/upload.js"

data变量

fileList: [],

methods方法

afterRead(res) {
    // 此时可以自行将文件上传至服务器
    console.log(res, "file");
    // base64格式赋值, data:image/jpeg;base64,/9j.......
    const data = res.content
    // 将 base64 编码的文件数据转为 Blob 对象
    const blob = base64ToBlob(data);
    // 获取文件名和 mime 类型
    const [filename, mimeType] = getFilenameAndMimetypeFromBase64(data);
    // 将 Blob 对象转换为 File 对象
    const file = new File([blob], res.file.name, { type: mimeType });
    // 写入formData
    const formData = new FormData();
    formData.append('file', file);
    // 执行上传方法
    uploadImg(formData).then(res => {
        console.log(res, "上传结果", this.fileList);
        this.form.files.push(res.data) // 写入form参数
    })
},

afterRead为vant组件 上传模块的回调
它的回调参数的content是一个base64图片 data:image/jpeg;base64,/9j.......

这段代码的文件名有可能会拿不到,毕竟是base64图片文件,所以filename可以自己定义,
在这里插入图片描述

// 获取文件名和 mime 类型
const [filename, mimeType] = getFilenameAndMimetypeFromBase64(res);
// 将 Blob 对象转换为 File 对象
const file = new File([blob], filename, { type: mimeType });

总结

除了base64格式的文件,可以用formData方式上传,别的例如文档doc、pdf也可以。
只要选择文件上传,拿到的回调参数里面,有一个是file类型的,那就是这个。
把这个file添加到formData,然后也是一样的上传。
如下

<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
    <el-upload class="upload-demo" :file-list="uploadFileList" drag
     :on-change="getFiles" 
    :on-remove="getFiles"
        action="" :auto-upload="false" multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
    </el-upload>
    <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitFileForm">确 定</el-button>
        <el-button @click="upload.open = false">取 消</el-button>
    </div>
</el-dialog>
// 提交上传文件
submitFileForm() {
    let formData = new FormData();
    this.files.forEach(f => formData.append("files", f.raw))
    fileUpload(formData).then(res => {
        this.$modal.msgSuccess("上传成功")
    })
    this.upload.open = false;
},
getFiles(file, fileList) {
    this.files = fileList;
},

在这里插入图片描述

### 如何在 Vue使用 Vant 实现拍照和图片上传功能 #### 使用 `van-uploader` 组件实现拍照并上传图片 为了实现在 Vue 项目中通过 Vant 进行拍照并上传图片的功能,可以利用 `van-uploader` 组件。此组件支持多种文件读取方式,并能处理本地图片预览以及服务器端的提交操作。 HTML 部分定义了一个简单的表单用于触发摄像头或相册选取: ```html <template> <div class="upload-container"> <!-- 图片上传控件 --> <van-uploader :after-read="handleRead" /> <!-- 显示已选中的图片 --> <img v-if="previewImage" :src="previewImage" alt="Preview Image"/> </div> </template> ``` JavaScript 方法负责处理用户选择后的逻辑,包括但不限于换为二进制数据、压缩图像尺寸等前置工作: ```javascript <script setup> import { ref } from 'vue'; import Compressor from 'compressorjs'; // 压缩库 const previewImage = ref(null); // 处理图片读取事件的方法 function handleRead(file) { const reader = new FileReader(); // 当文件加载完成时执行回调函数 reader.onloadend = () => { let resultFile; if (file instanceof Blob) { resultFile = file; // 创建临时 URL 来展示所选图片 previewImage.value = window.URL.createObjectURL(resultFile); // 对图片进行压缩处理 new Compressor(resultFile, { quality: 0.6, success(compressedResult) { uploadToServer(compressedResult); // 将压缩后的结果发送给服务端 }, error(err) { console.log(err.message); } }); } }; // 如果是 File 类型,则直接base64 或者 blob 数据;如果是其他类型则跳过这一步骤 if (file.file) { reader.readAsArrayBuffer(file.file); } else { previewImage.value = file.content; uploadToServer(file.file); } } async function uploadToServer(blobData) { try { const formData = new FormData(); formData.append('image', blobData, `${Date.now()}.jpg`); await fetch('/api/upload-image', { method: 'POST', body: formData }); alert('Upload successful!'); } catch(error){ console.error('Failed to upload image:', error); } } </script> ``` 上述代码实现了基本的照片拍摄/挑选流程[^1],并通过引入第三方插件来优化用户体验,比如自动调整方向防止照片被错误旋[^2]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿民不加班

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值