我怎样才能将我的JS对象转换为FormData?

我这样做的原因是,我有一个用~100个表单字段值构造的对象。

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

现在我被要求将上传文件功能添加到我的表单,当然,通过JSON是不可能的,所以我计划移动到FormData。那么有什么方法可以将我的JS对象转换为FormData呢?


当前回答

使用jquery,你可以通过$.param(obj)简单地做到这一点。

例子: Const obj = { 描述:'Some Item', 价格:0.00, srate:“0.00”, 颜色:红色的 } Const form_obj = $.param(obj); . ajax({美元 url:“example.com”, 方法:“文章”, 数据:form_obj }) < script src = " https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js " > < /脚本>

其他回答

在我的例子中,我的对象也有属性,即文件数组。因为它们是二进制的,所以应该以不同的方式处理——索引不需要是键的一部分。所以我修改了@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;
}

尝试JSON。函数如下所示

var postData = JSON.stringify(item);
var formData = new FormData();
formData.append("postData",postData );