ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

refine v3 Base64 文件上传:在表单提交前将文件转换为 Base64 字符串

refine v3 Base64 文件上传:在表单提交前将文件转换为 Base64 字符串 refine v3 Base64 文件上传在表单提交前将文件转换为 Base64 字符串【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine本篇技术指南介绍 refinev3Advanced Tutorials 中 Base64 Upload 的完整实现利用 Ant DesignForm组件的onFinish属性在表单提交前把Upload控件中的文件逐一转换为 Base64 字符串再连同表单数据一起交给 refine 的useForm提交流程。读完后你将掌握file2Base64与getValueFromEvent两个工具函数的用法、beforeUpload{() false}的拦截机制以及如何在 Create / Edit 两种页面中复用同一套 Base64 上传逻辑。为什么需要 Base64 上传很多后端接口并不直接接收multipart/form-data中的二进制文件而是期望在 JSON 请求体中携带文件的 Base64 编码字符串例如data:image/png;base64,iVBORw0KGgo...。典型场景包括后端通过 JSON 字段直接落库或推送到对象存储如某些 Strapi、Supabase 集成场景网关或反序列化层只接受 JSON不接受混合内容的 multipart 请求头像、附件等小体积文件开发者希望在一次POST中完成业务数据 文件的整体提交。refine 的解决方案是在表单onFinish触发时、真正调用 mutation 之前把Form收集到的UploadFile[]转换为携带base64String字段的对象数组。官方文档documentation/versioned_docs/version-3.xx.xx/advanced-tutorials/upload/base64-upload.md明确给出了这一思路By encoding your files and images from your forms to Base64 you can change all files needed for the upload to Base64 format before the submit。完整示例Create 页面中的 Base64 上传以下代码完整继承自官方文档上传字段为avatar多文件拖拽上传// pages/users/create.tsx import { //highlight-start file2Base64, //highlight-end } from pankod/refine-core; import { Create, Form, Upload, Input, useForm, // highlight-start getValueFromEvent, // highlight-end } from pankod/refine-antd; export const UserCreate: React.FC () { const { form, formProps, saveButtonProps } useFormIUser(); return ( Create saveButtonProps{saveButtonProps} Form {...formProps} layoutvertical // highlight-start onFinish{async (values) { const base64Files []; // ts-ignore const { avatar } values; for (const file of avatar) { if (file.originFileObj) { const base64String await file2Base64(file); base64Files.push({ ...file, base64String, }); } else { base64Files.push(file); } } return ( formProps.onFinish formProps.onFinish({ ...values, avatar: base64Files, }) ); }} // highlight-end Form.Item labelFirst Name namefirstName rules{[ { required: true, }, ]} Input / /Form.Item Form.Item labelAvatar Form.Item nameavatar valuePropNamefileList // highlight-start getValueFromEvent{getValueFromEvent} noStyle rules{[ { required: true, }, ]} Upload.Dragger listTypepicture multiple // highlight-start beforeUpload{() false} p classNameant-upload-text Drag drop a file in this area /p /Upload.Dragger /Form.Item /Form.Item /Form /Create ); }; interface IUser { id: number; firstName: string; avatar: [ { uid: string; name: string; url: string; status: error | success | done | uploading | removed; }, ]; }核心代码逐段解析1. 用onFinish包裹并替换提交流程关键点在于Form {...formProps}useForm返回的formProps中已经内置了一个onFinish它负责把校验通过的表单值交给useForm内部的 mutationonMutate。这里的做法是在展开formProps之后再显式传入自定义onFinish让它覆盖wrapper掉默认实现遍历values.avatar即 antd 的UploadFile[]对每个文件调用await file2Base64(file)得到 DataURL 形式的 Base64 字符串生成base64Files数组其中每个元素在原UploadFile基础上追加base64String字段最后调用formProps.onFinish?.({...values, avatar: base64Files})把转换后的完整表单值交还 refine 的提交流程。这样dataProvider最终收到的variables中avatar就是带base64String的对象数组后端可直接从 JSON 中解码保存。2.originFileObj区分新文件与已有文件if (file.originFileObj) { const base64String await file2Base64(file); base64Files.push({ ...file, base64String }); } else { base64Files.push(file); }originFileObj是 antdUpload为本次会话中用户新选择的原始File对象保留的引用。file2Base64内部依赖FileReader.readAsDataURL(file.originFileObj as Blob)只有持有原始Blob才能读取二进制内容。对于从后端加载回来的已有文件例如编辑页回显的 URL没有originFileObj也无需重新编码——直接透传即可。这也是为什么示例在 Edit 场景下可以不改剩余代码工作见下文Create 与 Edit 复用一节。3.getValueFromEvent与valuePropNamefileList内层Form.Item上的两个属性是 antd 上传控件接入 Form 的标准姿势valuePropNamefileList告诉 Form 用fileList属性而非默认的value绑定子组件getValueFromEvent{getValueFromEvent}把Upload的onChange事件参数UploadChangeParam归一化为UploadFile[]存进表单值。refine-antd 包对该函数的实现非常简洁可以直接在源码中确认packages/antd/src/definitions/upload/index.tsimport type { UploadFile, UploadChangeParam } from antd/lib/upload/interface; export const getValueFromEvent (event: UploadChangeParam): UploadFile[] { const { fileList } event; return [...fileList]; };即从事件参数中取出fileList并浅拷贝后作为表单值返回保证Form拿到的是不可变的新数组引用从而正确触发受控更新。4.beforeUpload{() false}拦截自动上传Upload.Dragger上的beforeUpload{() false}是 antd 的约定返回false会阻止控件自身发起任何网络上传请求。这很重要——文件只停留在前端内存中真正的提交由 refine 的onFinish统一完成。若漏写这一行antd 会尝试按其默认action单独上传文件导致提交行为失控。源码级原理file2Base64是怎么工作的file2Base64定义在 core 包的upload定义目录中实现如下packages/core/src/definitions/upload/file2Base64/index.tsexport const file2Base64 (file: any): Promisestring { return new Promise((resolve, reject) { const reader new FileReader(); const resultHandler () { if (reader.result) { reader.removeEventListener(load, resultHandler, false); resolve(reader.result as string); } }; reader.addEventListener(load, resultHandler, false); reader.readAsDataURL(file.originFileObj as Blob); reader.onerror (error) { reader.removeEventListener(load, resultHandler, false); return reject(error); }; }); };从源码结构看有三个值得注意的实现细节基于FileReader.readAsDataURLreader.result是完整的 DataURL 字符串含data:mime;base64,前缀因此后端拿到的base64String可直接解析出 MIME 类型与编码内容无需额外传输 MIME输入约定是 antd 风格的UploadFile函数签名虽然是file: any但实现里直接读取file.originFileObj。这与示例中传入选中的 antd 文件对象保持一致——如果你传入原生File对象originFileObj为undefinedreadAsDataURL(undefined)将无法正常读取事件监听的生命周期管理load成功后会removeEventListener错误分支同样移除监听并reject避免 Promise 悬挂或监听器泄漏。该函数的单元测试位于 packages/core/src/definitions/upload/file2Base64/index.spec.ts通过 mockwindow.FileReader验证了成功路径readAsDataURL触发addEventListener注册的回调后file2Base64正确 resolve 出reader.result测试断言expect(content).toBe(file content)。值得一提的是pankod/refine-antd也内置了一份等价实现packages/antd/src/definitions/upload/index.ts只是参数类型标注为UploadFile。文档示例选择从 core 包导入保持了对具体 UI 框架包的最小依赖面。Create 与 Edit 复用改一个组件即可官方文档特别提示把Create换成Edit其余代码一行不改即可得到编辑页的 Base64 上传。原因在于useForm在 Edit 模式下会自动query当前记录并把返回值作为表单初始值注入回显出来的已有文件对象没有originFileObj走else分支原样透传用户在编辑页新添加的文件带有originFileObj会被转换为base64String一并提交。仓库中的示例工程 examples/upload-antd-base64 完整演示了这一模式create.tsx 与同目录下的 edit.tsx 使用了完全相同的onFinish转换逻辑。该示例中还定义了表单变量的类型约束examples/upload-antd-base64/src/interfaces/index.d.tsexport interface IUserVariable { id: number; email: string; firstName: string; lastName: string; avatar: UploadFile[]; }将avatar显式标注为UploadFile[]后useFormIUser, HttpError, IUserVariable的第三个泛型即可精确描述提交变量结构避免文档示例中// ts-ignore的权宜写法。注意事项与适用边界Base64 体积膨胀Base64 编码会使数据体积增加约 33%每 3 字节变 4 字符。该方案适合头像、图标等中小体积文件大文件或批量文件建议改用 multipart/form-data 上传refine 在 multipart-upload.md 中提供了对应的进阶教程浏览器 API 依赖file2Base64依赖FileReader只能在浏览器或具备 DOM 环境的测试运行时中使用包名适用前提本文对应 refine v3 文档versioned_docs/version-3.xx.xx包名为pankod/refine-core/pankod/refine-antd仓库中的examples/upload-antd-base64示例已升级到refinedev/*命名逻辑完全一致迁移时只需替换导入路径请求体大小限制Base64 字符串走 JSON 请求体注意后端网关、Nginx 等中间件对Content-Length的限制配置。小结Base64 上传的本质是一次提交前的数据整形借助 antdForm的onFinish覆盖机制把Upload组件收集到的UploadFile[]逐个通过file2Base64转换为携带base64String的纯数据再交还useForm的 mutation 流程。整套方案只需要一个异步onFinish、两个 refine 工具函数file2Base64、getValueFromEvent和一个beforeUpload{() false}拦截即可让 Create / Edit 两种页面以同一套代码完成 Base64 文件提交。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表