js文件上传图片并支持本地预览

前端实现文件上传功能,首先通过input标签的change事件拿到上传的文件对象,最后读取文件内容将图片转成base64格式实现本地预览,再将base64转成file对象实现上传,base64转file具体有两种实现方式:

方法一:直接将base64转换为file对象,首先通过base64获取文件类型,并将base64通过atob解码为二进制数据,最后通过new File()创建对象。代码如下:

/**
 * 
 * @param base64 base64字符串
 * @param fileName 文件名称
 * @returns 返回文件对象
 */
const base64ToFile = (base64: string, fileName: string) => {
  const arr = base64.split(',');
  const mime = arr[0]?.match(/:(.*?);/)?.[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], fileName, { type: mime });
};

方法二:将base64转成blob对象,然后通过formData.get('file')来获取文件对象,代码如下:

/**
 * 
 * @param dataUrl base64格式的字符串
 * @returns 返回blob对象
 */
const dataUrlToBlob = (dataUrl: any) => {
  let arr = dataUrl.split(',');
  console.log(arr[0]);
  let mime = arr[0].match(/:(.*?);/)[1];
  let bstr = atob(arr[1]);
  const arrBuff = new ArrayBuffer(bstr.length);
  return new Blob([arrBuff], { type: mime });
};

方法一和方法二均可,具体使用哪一种方式可以根据个人偏好选择,最终实现的上传函数如下:

import { ChangeEvent } from 'react';

/**
 *
 * @param ev input对象
 * @param {Array<string>} fileType 支持上传的文件类型
 * @param {number} maxSize 支持上传的文件最大值
 * @returns Promise
 */
const UploadFile = (
  ev: ChangeEvent<HTMLInputElement>,
  fileType = ['image/jpeg', 'image/jpg', 'image/png'],
  maxSize = 2
): Promise<{ base64: string; file: any }> => {
  return new Promise((resolve, reject) => {
    const files = ev.target?.files || [];
    // console.log('files[0]=====', files[0]);
    if (!files.length) return;
    // 判断文件类型是否符合规定的格式
    if (!fileType.includes(files[0].type)) {
      ev.target.value = '';
      return reject('上传的图片格式有误,请重新上传');
    }
    if (files[0].size > 1024 * 1024 * maxSize) {
      ev.target.value = '';
      return reject('允许上传的图片最大为2MB');
    }
    // 如果不需要本地预览可以直接在这里执行resolve方法
    // resolve({file: files[0]});
    const fileName = files[0].name; // 保存文件名,如果需求需要原文件名需要返回出去
    // 通常文件上传需要本地预览,因此需要将文件对象转成base64进行本地预览
    const reader = new FileReader();
    reader.readAsDataURL(files[0]);
    reader.onload = (event: any) => {
      ev.target.value = '';
      // 采用方法一
      const file = base64ToFile(event.target.result, fileName);
      resolve({ base64: event.target.result, file });
      // 采用方法二
      // const formData = new FormData();
      // formData.append('file', dataUrlToBlob(event.target.result), fileName);
      // resolve({ base64: event.target.result, file: formData.get('file') });
    };
  });
};

最终调用代码如下:

const handleUpload = (event: ChangeEvent<HTMLInputElement>) => {
		console.log(event)
		UploadFile(event).then((res) => {
			console.log('first', res)
			const formData = new FormData();
			formData.append('file', res.file);
			console.log('formData===', formData)
		}).catch((err) => {
			console.log(err)
		})
	}


<input
        type='file'
        onChange={handleUpload}
        // accept='image/jpeg,image/jpg,image/png'
      />

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值