表单序列化 javascript (没有框架)

想知道在没有 jquery 的 javascript 中是否有一个函数或者任何框架允许我序列化表单并访问序列化版本?

255667 次浏览

微型 从序列化库不依赖于框架。除此之外,您还需要自己实现序列化函数。(不过在1.2 KB 的重量下,为什么不使用它呢?)

function serialize (form) {
if (!form || form.nodeName !== "FORM") {
return;
}
var i, j, q = [];
for (i = form.elements.length - 1; i >= 0; i = i - 1) {
if (form.elements[i].name === "") {
continue;
}
switch (form.elements[i].nodeName) {
case 'INPUT':
switch (form.elements[i].type) {
case 'text':
case 'tel':
case 'email':
case 'hidden':
case 'password':
case 'button':
case 'reset':
case 'submit':
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
break;
case 'checkbox':
case 'radio':
if (form.elements[i].checked) {
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
}
break;
}
break;
case 'file':
break;
case 'TEXTAREA':
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
break;
case 'SELECT':
switch (form.elements[i].type) {
case 'select-one':
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
break;
case 'select-multiple':
for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) {
if (form.elements[i].options[j].selected) {
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value));
}
}
break;
}
break;
case 'BUTTON':
switch (form.elements[i].type) {
case 'reset':
case 'submit':
case 'button':
q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
break;
}
break;
}
}
return q.join("&");
}

资料来源: http://code.google.com/p/form-serialize/source/browse/trunk/serialize-0.1.js

我从约翰戴夫 · 迪卡诺的回答开始。

这应该解决一些问题提到的答复他的职能。

  1. 用 + 符号替换% 20。
  2. 只有单击了 Submit/Button 类型,才会提交它们 提交表格。
  3. 将忽略重置按钮。
  4. 这段代码对我来说似乎是多余的,因为它实际上是在执行 无论字段类型如何,都是一样的 与 HTML5字段类型(如‘ tel’和‘ email’)不兼容, 因此我用 switch 语句删除了大部分细节。

如果按钮类型没有名称值,它们仍将被忽略。

function serialize(form, evt){
var evt    = evt || window.event;
evt.target = evt.target || evt.srcElement || null;
var field, query='';
if(typeof form == 'object' && form.nodeName == 'FORM'){
for(i=form.elements.length-1; i>=0; i--){
field = form.elements[i];
if(field.name && field.type != 'file' && field.type != 'reset' && !field.disabled){
if(field.type == 'select-multiple'){
for(j=form.elements[i].options.length-1; j>=0; j--){
if(field.options[j].selected){
query += '&' + field.name + "=" + encodeURIComponent(field.options[j].value).replace(/%20/g,'+');
}
}
}
else{
if((field.type != 'submit' && field.type != 'button') || evt.target == field){
if((field.type != 'checkbox' && field.type != 'radio') || field.checked){
query += '&' + field.name + "=" + encodeURIComponent(field.value).replace(/%20/g,'+');
}
}
}
}
}
}
return query.substr(1);
}

这就是我目前使用这个函数的方式。

<form onsubmit="myAjax('http://example.com/services/email.php', 'POST', serialize(this, event))">
var form = document.querySelector('form');
var data = new FormData(form);
var req = new XMLHttpRequest();
req.send(data);

虽然它似乎只对 POST 请求有效。

Https://developer.mozilla.org/en-us/docs/web/api/formdata

下面是 TibTibs 的一个稍作修改的版本:

function serialize(form) {
var field, s = [];
if (typeof form == 'object' && form.nodeName == "FORM") {
var len = form.elements.length;
for (i=0; i<len; i++) {
field = form.elements[i];
if (field.name && !field.disabled && field.type != 'file' && field.type != 'reset' && field.type != 'submit' && field.type != 'button') {
if (field.type == 'select-multiple') {
for (j=form.elements[i].options.length-1; j>=0; j--) {
if(field.options[j].selected)
s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.options[j].value);
}
} else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) {
s[s.length] = encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value);
}
}
}
}
return s.join('&').replace(/%20/g, '+');
}

被禁用的字段被丢弃,名称也被 URL 编码。在返回字符串之前,% 20字符的正则表达式替换只发生一次。

查询字符串的形式与 jQuery 的 $. Series ()方法的结果相同。

如果你想序列化一个事件的输入,这里有一个纯 JavaScript 的方法。

// serialize form
var data = {};
var inputs = [].slice.call(e.target.getElementsByTagName('input'));
inputs.forEach(input => {
data[input.name] = input.value;
});

数据将是输入的 JavaScript 对象。

@ SimonSteinberger 代码的重构版本,使用了更少的变量,并利用了 forEach循环的速度(比 for快一点)

function serialize(form) {
var result = [];
if (typeof form === 'object' && form.nodeName === 'FORM')
Array.prototype.slice.call(form.elements).forEach(function(control) {
if (
control.name &&
!control.disabled &&
['file', 'reset', 'submit', 'button'].indexOf(control.type) === -1
)
if (control.type === 'select-multiple')
Array.prototype.slice.call(control.options).forEach(function(option) {
if (option.selected)
result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(option.value));
});
else if (
['checkbox', 'radio'].indexOf(control.type) === -1 ||
control.checked
) result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(control.value));
});
return result.join('&').replace(/%20/g, '+');
}

我把 TibTibs 的答案重构成了一个更易于阅读的东西。由于80个字符的宽度和一些注释,它稍微长一些。

此外,它忽略空白字段名称和空白值。

// Serialize the specified form into a query string.
//
// Returns a blank string if +form+ is not actually a form element.
function $serialize(form, evt) {
if(typeof(form) !== 'object' && form.nodeName !== "FORM")
return '';


var evt    = evt || window.event || { target: null };
evt.target = evt.target || evt.srcElement || null;
var field, query = '';


// Transform a form field into a query-string-friendly
// serialized form.
//
// [NOTE]: Replaces blank spaces from its standard '%20' representation
//         into the non-standard (though widely used) '+'.
var encode = function(field, name) {
if (field.disabled) return '';


return '&' + (name || field.name) + '=' +
encodeURIComponent(field.value).replace(/%20/g,'+');
}


// Fields without names can't be serialized.
var hasName = function(el) {
return (el.name && el.name.length > 0)
}


// Ignore the usual suspects: file inputs, reset buttons,
// buttons that did not submit the form and unchecked
// radio buttons and checkboxes.
var ignorableField = function(el, evt) {
return ((el.type == 'file' || el.type == 'reset')
|| ((el.type == 'submit' || el.type == 'button') && evt.target != el)
|| ((el.type == 'checkbox' || el.type == 'radio') && !el.checked))
}


var parseMultiSelect = function(field) {
var q = '';


for (var j=field.options.length-1; j>=0; j--) {
if (field.options[j].selected) {
q += encode(field.options[j], field.name);
}
}


return q;
};


for(i = form.elements.length - 1; i >= 0; i--) {
field = form.elements[i];


if (!hasName(field) || field.value == '' || ignorableField(field, evt))
continue;


query += (field.type == 'select-multiple') ? parseMultiSelect(field)
: encode(field);
}


return (query.length == 0) ? '' : query.substr(1);
}
HTMLElement.prototype.serialize = function(){
var obj = {};
var elements = this.querySelectorAll( "input, select, textarea" );
for( var i = 0; i < elements.length; ++i ) {
var element = elements[i];
var name = element.name;
var value = element.value;


if( name ) {
obj[ name ] = value;
}
}
return JSON.stringify( obj );
}

这样使用:

var dataToSend = document.querySelector("form").serialize();

我希望我帮上忙了。

只适用于现代浏览器

如果您的目标浏览器支持 URLSearchParams API (最新的浏览器)和 FormData(formElement)构造函数(最新的浏览器) ,请使用:

new URLSearchParams(new FormData(formElement)).toString()

除了 IE

对于支持 URLSearchParams但不支持 FormData(formElement)构造函数的浏览器,使用 填写本表格和下面的代码(除了 IE 以外,其他浏览器都可以使用) :

new URLSearchParams(Array.from(new FormData(formElement))).toString()

例子

var form = document.querySelector('form');
var out = document.querySelector('output');


function updateResult() {
try {
out.textContent = new URLSearchParams(Array.from(new FormData(form)));
out.className = '';
} catch (e) {
out.textContent = e;
out.className = 'error';
}
}


updateResult();
form.addEventListener('input', updateResult);
body { font-family: Arial, sans-serif; display: flex; flex-wrap: wrap; }
input[type="text"] { margin-left: 6px; max-width: 30px; }
label + label { margin-left: 10px; }
output { font-family: monospace; }
.error { color: #c00; }
div { margin-right: 30px; }
<!-- FormData polyfill for older browsers -->
<script src="https://unpkg.com/formdata-polyfill@3.0.17/formdata.min.js"></script>
<div>
<h3>Form</h3>
<form id="form">
<label>x:<input type="text" name="x" value="1"></label>
<label>y:<input type="text" name="y" value="2"></label>
<label>
z:
<select name="z">
<option value="a" selected>a</option>
<option value="b" selected>b</option>
</select>
</label>
</form>
</div>
<div>
<h3>Query string</h3>
<output for="form"></output>
</div>

与 IE 10兼容

对于更老的浏览器(例如 IE10) ,使用 表格数据填充,如果必要的话使用 Array.from填充,以及下面的代码:

Array.from(
new FormData(formElement),
function(e) { return e.map(encodeURIComponent).join('='); }
).join('&')

如果你需要使用 json 格式的 POST 提交表单“ myForm”,你可以这样做:

const formEntries = new FormData(myForm).entries();
const json = Object.assign(...Array.from(formEntries, ([x,y]) => ({[x]:y})));
fetch('/api/foo', {
method: 'POST',
body: JSON.stringify(json)
});

第二行从数组转换如下:

[["firstProp", "firstValue"], ["secondProp", "secondValue"], ...and so on... ]

变成一个普通的物体,比如:

{"firstProp": "firstValue", "secondProp": "secondValue", ...and so on ... }

... 它通过传递一个 mapFn 到 Array.from ()来完成这个转换。这个 mapFn 应用于每个[“ a”,“ b”]对,并将它们转换为{“ a”: “ b”} ,以便数组包含许多对象,每个对象中只有一个属性。MapFn 使用“解构”来获取对的第一部分和第二部分的名称,它还使用 ES6“ ComputedPropertyName”来设置由 mapFn 返回的对象中的属性名称(这就是为什么说“[ x ] : something”而不仅仅是“ x: something”。

然后将所有这些单个属性对象传递到 Object.sign ()函数的参数中,该函数将所有单个属性对象合并到具有所有属性的单个对象中。

数组 from () : Https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/array/from

参数解构: Https://simonsmith.io/destructuring-objects-as-function-parameters-in-es6/

更多关于计算属性名称的资料: 变量作为 JavaScript 对象文字中的属性名称?

  // supports IE8 and IE9
function serialize(form) {
var inputs = form.elements;
var array = [];
for(i=0; i < inputs.length; i++) {
var inputNameValue = inputs[i].name + '=' + inputs[i].value;
array.push(inputNameValue);
}
return array.join('&');
}
//using the serialize function written above
var form = document.getElementById("form");//get the id of your form. i am assuming the id to be named form.
var form_data = serialize(form);
var xhr = new XMLHttpRequest();
xhr.send(form_data);


//does not work with IE8 AND IE9
var form = document.querySelector('form');
var data = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.send(data);

我已经从@moison 的答案中获取了 formData 的 entry ()方法,从 MDN中得到的结果是:

Entry ()方法返回允许运行的迭代器 通过此对象中包含的所有键/值对 P 是一个 USVString 对象; 值可以是一个 USVString,也可以是一个 Blob。

但唯一的问题是移动浏览器(不支持 android 和 Safari)以及 IE 和 Safari 桌面

但基本上我的方法是这样的:

let theForm =  document.getElementById("contact");


theForm.onsubmit = function(event) {
event.preventDefault();


let rawData = new FormData(theForm);
let data = {};


for(let pair of rawData.entries()) {
data[pair[0]] = pair[1];
}
let contactData = JSON.stringify(data);
console.warn(contactData);
//here you can send a post request with content-type :'application.json'


};

代码可以找到 给你

适用于所有浏览器。

const formSerialize = formElement => {
const values = {};
const inputs = formElement.elements;


for (let i = 0; i < inputs.length; i++) {
values[inputs[i].name] = inputs[i].value;
}
return values;
}


const dumpValues = form => () => {
  

const r = formSerialize(form);
console.log(r);
console.log(JSON.stringify(r));
}


const form = document.querySelector('form');


dumpValues(form)();


form.addEventListener('change',dumpValues(form));
<form action="/my-handling-form-page" method="post">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="user_name" value="John">
</div>
<div>
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_mail" value="john@jonhson.j">
</div>
<div>
<label for="interests">Interest:</label>
<select required=""  id="interests" name="interests">
<option value="" selected="selected">- None -</option>
<option value="drums">Drums</option>
<option value="js">Javascript</option>
<option value="sports">Sports</option>
<option value="trekking">Trekking</option>
</select>
</div>
<div>
<label for="msg">Message:</label>
<textarea id="msg" name="user_message">Hello My Friend</textarea>
</div>
</form>

出于调试的目的,这可能对您有所帮助:

function print_form_data(form) {
const form_data = new FormData(form);


for (const item of form_data.entries()) {
console.log(item);
}


return false;
}

我可能是疯了,但我发现这些答案实在是太浮夸了。这是我的解决办法

function serialiseForm(form) {
var input = form.getElementsByTagName("input");
var formData = {};
for (var i = 0; i < input.length; i++) {
formData[input[i].name] = input[i].value;
}
return formData = JSON.stringify(formData);
}

使用 JavaScript reduce 函数对所有浏览器都有效,包括 IE9 > :

Array.prototype.slice.call(form.elements) // convert form elements to array
.reduce(function(acc,cur){   // reduce
var o = {type : cur.type, name : cur.name, value : cur.value}; // get needed keys
if(['checkbox','radio'].indexOf(cur.type) !==-1){
o.checked = cur.checked;
} else if(cur.type === 'select-multiple'){
o.value=[];
for(i=0;i<cur.length;i++){
o.value.push({
value : cur.options[i].value,
selected : cur.options[i].selected
});
}
}
acc.push(o);
return acc;
},[]);

下面是实例。

var _formId = document.getElementById('formId'),
formData = Array.prototype.slice.call(_formId.elements).reduce(function(acc,cur,indx,arr){
var i,o = {type : cur.type, name : cur.name, value : cur.value};
if(['checkbox','radio'].indexOf(cur.type) !==-1){
o.checked = cur.checked;
} else if(cur.type === 'select-multiple'){
o.value=[];
for(i=0;i<cur.length;i++){
o.value.push({
value : cur.options[i].value,
selected : cur.options[i].selected
});
}
}
acc.push(o);
return acc;
},[]);


// view
document.getElementById('formOutput').innerHTML = JSON.stringify(formData, null, 4);
<form id="formId">
<input type="text" name="texttype" value="some text">
<select>
<option value="Opt 1">Opt 1</option>
<option value="Opt 2" selected>Opt 2</option>
<option value="Opt 3">Opt 3</option>
</select>
<input type="checkbox" name="checkboxtype" value="Checkbox 1" checked> Checkbox 1
<input type="checkbox" name="checkboxtype" value="Checkbox 2"> Checkbox 2
<input type="radio" name="radiotype" value="Radio Btn 1"> Radio Btn 1
<input type="radio" name="radiotype" value="Radio Btn 2" checked> Radio Btn 2
<select multiple>
<option value="Multi 1" selected>Multi 1</option>
<option value="Multi 2">Saab</option>
<option value="Multi 3" selected>Multi 3</option>
</select>
</form>
<pre><code id="formOutput"></code></pre>

我希望能成功

var serializeForm = (formElement) => {
const formData = {};
const inputs = formElement.elements;


for (let i = 0; i < inputs.length; i++) {
if(inputs[i].name!=="")
formData[inputs[i].name] = inputs[i].value;
}
return formData;
}

改进 David Lemon 的回答。

这将表单数据转换为 JSON,并允许您从数据对象设置表单。

const main = () => {
const form = document.forms['info'];
const data = {
"user_name"       : "John",
"user_email"      : "john@jonhson.com",
"user_created"    : "2020-03-24",
"user_age"        : 42,
"user_subscribed" : true,
"user_interests"  : "sports",
"user_message"    : "Hello My Friend"
};


populateForm(form, data);
updateJsonView(form);
form.addEventListener('change', (e) => updateJsonView(form));
}


const getFieldValue = (field, opts) => {
let type = field.getAttribute('type');
if (type) {
switch (type) {
case 'checkbox':
return field.checked;
case 'number':
return field.value.includes('.')
? parseFloat(field.value)
: parseInt(field.value, 10);
}
}
if (opts && opts[field.name] && opts[field.name].type) {
switch (opts[field.name].type) {
case 'int':
return parseInt(field.value, 10);
case 'float':
return parseFloat(field.value);
}
}
return field.value;
}


const setFieldValue = (field, value) => {
let type = field.getAttribute('type');
if (type) {
switch (type) {
case 'checkbox':
field.checked = value;
break;
default:
field.value = value;
break;
}
} else {
field.value = value;
}
}


const extractFormData = (form, opts) => {
return Array.from(form.elements).reduce((data, element) => {
return Object.assign(data, { [element.name] : getFieldValue(element, opts) });
}, {});
};


const populateForm = (form, data) => {
return Array.from(form.elements).forEach((element) => {
setFieldValue(element, data[element.name]);
});
};


const updateJsonView = (form) => {
let fieldOptions = {};
let formData = extractFormData(form, fieldOptions);
let serializedData = JSON.stringify(formData, null, 2);
document.querySelector('.json-view').textContent = serializedData;
};


main();
.form-field {
margin-bottom: 0.5em;
}


.form-field label {
display: inline-block;
font-weight: bold;
width: 7em;
vertical-align: top;
}


.json-view {
position: absolute;
top: 0.667em;
right: 0.667em;
border: thin solid grey;
padding: 0.5em;
white-space: pre;
font-family: monospace;
overflow: scroll-y;
max-height: 100%;
}
<form name="info" action="/my-handling-form-page" method="post">
<div class="form-field">
<label for="name">Name:</label>
<input type="text" id="name" name="user_name">
</div>
<div class="form-field">
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_email">
</div>
<div class="form-field">
<label for="created">Date of Birth:</label>
<input type="date" id="created" name="user_created">
</div>
<div class="form-field">
<label for="age">Age:</label>
<input type="number" id="age" name="user_age">
</div>
<div class="form-field">
<label for="subscribe">Subscribe:</label>
<input type="checkbox" id="subscribe" name="user_subscribed">
</div>
<div class="form-field">
<label for="interests">Interest:</label>
<select required=""  id="interests" name="user_interests">
<option value="" selected="selected">- None -</option>
<option value="drums">Drums</option>
<option value="js">Javascript</option>
<option value="sports">Sports</option>
<option value="trekking">Trekking</option>
</select>
</div>
<div class="form-field">
<label for="msg">Message:</label>
<textarea id="msg" name="user_message"></textarea>
</div>
</form>
<div class="json-view"></div>

这可以通过如下非常简单的函数来完成

function serialize(form) {
let requestArray = [];
form.querySelectorAll('[name]').forEach((elem) => {
requestArray.push(elem.name + '=' + elem.value);
});
if(requestArray.length > 0)
return requestArray.join('&');
else
return false;
}


serialized = serialize(document.querySelector('form'))
console.log(serialized);
<form>


<input type='text' name='fname' value='Johne'/>
<input type='text' name='lname' value='Doe'/>
<input type='text' name='contact[]' value='99999999'/>
<input type='text' name='contact[]' value='34423434345'/>


</form>

以下是纯 JavaScript 方法:

var form = document.querySelector('form');
var data = new FormData(form);


var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
xhttp.open("POST", "<YOUR-URL>", true);
xhttp.send(data);
}

我的方式。

const myForm = document.forms['form-name']


myForm.onsubmit=e=>
{
e.preventDefault()  // for testing...


let data = Array.from(new FormData(myForm))
.reduce((r,[k,v])=>{r[k]=v;return r},{})


/*_______________________________________ same code: for beginners
let data = {}
Array.from(new FormData(myForm), (entry) => { data[ entry[0] ] = entry[1]} )
________________________________________________________________*/
 

console.log(data)
  

//...
}

我喜欢这个库: https://github.com/macek/jquery-serialize-object(1.7 KB)

给定一个基本的 HTML 表单:

<form id="contact">
<input name="user[email]" value="jsmith@example.com">
<input name="user[pets][]" type="checkbox" value="cat" checked>
<input name="user[pets][]" type="checkbox" value="dog" checked>
<input name="user[pets][]" type="checkbox" value="bird">
<input type="submit">
</form>

. seralizeObject ー将选定的表单序列化为 JavaScript 对象

$('form#contact').serializeObject();
//=> {user: {email: "jsmith@example.com", pets: ["cat", "dog"]}}

主要款式

将值推送到数组

<input name="foo[]" value="a">
<input name="foo[]" value="b">
$("form").serializeObject();
//=> {foo: [a, b]}

修正 ー向指定索引处的数组添加值

<input name="foo[2]" value="a">
<input name="foo[4]" value="b">
$("form").serializeObject();
//=> {foo: [, , "a", , "b"]}

名为 ー将值添加到指定的键

<input name="foo[bar]" value="a">
<input name="foo[bof]" value="b">
<input name="hello" value="world">
$("form").serializeObject();
//=> {foo: {bar: "a", bof: "b"}, hello: "world"}

类似的库(更有生命力) : https://github.com/marioizquierdo/jquery.serializeJSON

类似的库(活得好好的) : < a href = “ https://github.com/brain fooong/form-data-json”rel = “ nofollow norefrer”> https://github.com/brainfoolong/form-data-json 使用最后一种方法,不仅可以序列化数据,反之亦然: 为表单字段设置值

这是我的解决办法

JsonStringifyForm: function(formId) {
let myForm = document.getElementById(formId);
let formData = new FormData(myForm);
const data = {}; // need to convert it before using not with XMLHttpRequest
for (let [key, val] of formData.entries()) {
Object.assign(data, { [key]: val });
}
return JSON.stringify(data);
}

您可以按照以下步骤使用 Object.FROM 条目

function parseForm(e) {
const formData = new FormData(e.target);
return Object.fromEntries(formData.entries());
}