我怎样才能将我的JS对象转换为FormData?
我这样做的原因是,我有一个用~100个表单字段值构造的对象。
var item = {
description: 'Some Item',
price : '0.00',
srate : '0.00',
color : 'red',
...
...
}
现在我被要求将上传文件功能添加到我的表单,当然,通过JSON是不可能的,所以我计划移动到FormData。那么有什么方法可以将我的JS对象转换为FormData呢?
在我的例子中,我的对象也有属性,即文件数组。因为它们是二进制的,所以应该以不同的方式处理——索引不需要是键的一部分。所以我修改了@Vladimir Novopashin和@developer033的答案:
export function convertToFormData(data, formData, parentKey) {
if(data === null || data === undefined) return null;
formData = formData || new FormData();
if (typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
Object.keys(data).forEach(key =>
convertToFormData(data[key], formData, (!parentKey ? key : (data[key] instanceof File ? parentKey : `${parentKey}[${key}]`)))
);
} else {
formData.append(parentKey, data);
}
return formData;
}
2022年更新
Axios现在支持将对象自动序列化为FormData
从0.27版开始,如果请求的Content-Type报头被设置为multipart/form-data, Axios就支持将对象自动序列化为FormData对象。阅读更多
嵌套对象和文件
下面的解决方案处理嵌套对象、数组和文件。
const buildFormData = (formData: FormData, data: FormVal, parentKey?: string) => {
if (Array.isArray(data)) {
data.forEach((el) => {
buildFormData(formData, el, parentKey)
})
} else if (typeof data === "object" && !(data instanceof File)) {
Object.keys(data).forEach((key) => {
buildFormData(formData, (data as FormDataNest)[key], parentKey ? `${parentKey}.${key}` : key)
})
} else {
if (isNil(data)) {
return
}
let value = typeof data === "boolean" || typeof data === "number" ? data.toString() : data
formData.append(parentKey as string, value)
}
}
export const getFormData = (data: Record<string, FormDataNest>) => {
const formData = new FormData()
buildFormData(formData, data)
return formData
}
类型
type FormDataPrimitive = string | Blob | number | boolean
interface FormDataNest {
[x: string]: FormVal
}
type FormVal = FormDataNest | FormDataPrimitive
我参考了古德拉丹的回答。我用Typescript格式编辑了一下。
class UtilityService {
private appendFormData(formData, data, rootName) {
let root = rootName || '';
if (data instanceof File) {
formData.append(root, data);
} else if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
this.appendFormData(formData, data[i], root + '[' + i + ']');
}
} else if (typeof data === 'object' && data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
if (root === '') {
this.appendFormData(formData, data[key], key);
} else {
this.appendFormData(formData, data[key], root + '.' + key);
}
}
}
} else {
if (data !== null && typeof data !== 'undefined') {
formData.append(root, data);
}
}
}
getFormDataFromObj(data) {
var formData = new FormData();
this.appendFormData(formData, data, '');
return formData;
}
}
export let UtilityMan = new UtilityService();
下面是一个非常简单的TypeScript实现,基于@Vladimir Novopashin和@developer033的回答。打印稿操场
type Serializeable =
| string
| number
| boolean
| null
| Date
| File
| { [x: string | number]: Serializeable }
| Array<Serializeable>;
function serialize(
data: Serializeable,
parentKey = '',
formData: FormData = new FormData()
): FormData {
if ( typeof data === 'string') {
formData.append(parentKey, data);
} else if ( typeof data === 'number') {
formData.append(parentKey, data.toString());
} else if ( typeof data === 'boolean') {
formData.append(parentKey, data ? 'true' : 'false');
} else if (data === null) {
formData.append(parentKey, 'null');
} else if (data instanceof Date) {
formData.append(parentKey, data.toISOString());
} else if (data instanceof File) {
formData.append(parentKey, data);
} else {
// Arrays and objects
Object.entries(data).forEach((entry: [string | number, Serializeable]) => {
const [key, value] = entry;
serialize(value, parentKey ? `${parentKey}[${key}]` : key.toString(), formData);
});
}
return formData;
}