[Vue2] Vant2 uploads files using formData method, base64 image to Blob and then to File upload


foreword

vant2 upload component portal
使用vant2组件中的uploader组件

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

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

1. The method of converting base64 to Blob object

Under the utils folder, create a tool js calledbase64toFile.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);
});
 */

The usage is in the above code, which is the following process

2. Use steps

1. Introduce tool js

The code is as follows (example):

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

2. Write formData upload method

Write your upload in a folder in src /api
insert image description here

The code is as follows (example):

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
    })
}

Modify the url address according to the actual situation,

3. The request code in the api method

Create a new one in the utils folderrequest.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 has many tool classes introduced, but general vue projects should have scaffolding, if you don’t have it, or if you haven’t seen this request.js, you can check the source code of Ruoyi background management system. Here is just an example, telling the encapsulation in the request method is these codes


3. Actual operation

1. HTML code

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

2. js code

import method

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

data variable

fileList: [],

methods method

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 is the callback of the vant component upload module
The content of its callback parameter is a base64 imagedata:image/jpeg;base64,/9j.......

The file name of this code may not be available. After all, it is a base64 image file, so the filename can be defined by yourself.
insert image description here

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

Summarize

In addition to files in base64 format, they can be uploaded using formData, and other documents such as doc and pdf are also available.
只要选择文件上传,拿到的回调参数里面,有一个是file类型的,那就是这个。
take thisfileAdd it to formData, and then upload it the same way.
as follows

<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;
},

insert image description here

Guess you like

Origin blog.csdn.net/qq_51055690/article/details/131479194