我怎样才能将我的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;
}
注意:这个答案并没有直接回答问题,而是给出了说明和替代方案。
人们通常使用FormData来允许他们上传文件,有三种方法可以做到这一点,我会在这个回答中详细提到它们。
1. 直接从表单中获取数据
为此,您需要在每个输入中拥有名称和值属性,然后告诉FormData从表单DOM中获取值;
let formData = new FormData(data.target as HTMLFormElement)
优点:
你不需要使用JS解决方案来获取这些值。
原生支持嵌套数据,数组等…
缺点:
您需要确保所有需要的数据都作为值属性添加到输入dom上
2. 用JS转换数据
如果你把值存储在变量中,那么你可以使用JS将它们附加到FormData中。
优点:
是否可以根据需要进行操作
你不需要在输入dom中有值属性
缺点:
自定义复杂JS附加嵌套数据到FormData对象
您需要将值存储在一个变量中
3.在单独的请求中上传文件
您可以为文件上传输入创建一个单独的表单。
优点:
您不需要等待上传提交
您不需要担心将所有数据追加到FormData对象,您只追加文件。
缺点:
在创建实体本身之前,您需要在后端处理这些上传
您需要在前端和后端处理删除文件
也许你正在寻找这个,一个代码,接收你的javascript对象,从它创建一个FormData对象,然后POST它到你的服务器使用新的Fetch API:
let myJsObj = {'someIndex': 'a value'};
let datos = new FormData();
for (let i in myJsObj){
datos.append( i, myJsObj[i] );
}
fetch('your.php', {
method: 'POST',
body: datos
}).then(response => response.json())
.then(objson => {
console.log('Success:', objson);
})
.catch((error) => {
console.error('Error:', error);
});
我可能有点晚了,但这就是我创建的将单个对象转换为FormData的方法。
function formData(formData, filesIgnore = []) {
let data = new FormData();
let files = filesIgnore;
Object.entries(formData).forEach(([key, value]) => {
if (typeof value === 'object' && !files.includes(key)) {
data.append(key, JSON.stringify(value) || null);
} else if (files.includes(key)) {
data.append(key, value[0] || null);
} else {
data.append(key, value || null);
}
})
return data;
}
它是如何工作的?
它将转换并返回所有属性,除了您在忽略列表中设置的File对象(第二个参数)。如果有人能告诉我一个更好的方法来确定这将有帮助!)变成一个json字符串使用json .stringify。然后在您的服务器上,您只需要将其转换回JSON对象。
例子:
let form = {
first_name: 'John',
last_name: 'Doe',
details: {
phone_number: 1234 5678 910,
address: '123 Some Street',
},
profile_picture: [object FileList] // set by your form file input. Currently only support 1 file per property.
}
function submit() {
let data = formData(form, ['profile_picture']);
axios.post('/url', data).then(res => {
console.log('object uploaded');
})
}
我仍然有点新的Http请求和JavaScript,所以任何反馈将高度赞赏!
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