使用 javascript 没有 jQuery 的简单 ajax 表单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6990729/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simple ajax form using javascript no jQuery
提问by calebo
I'm working with a form for which the mark-up I can't change & can't use jQuery. Currently the form post the results to a new window. Is it possible to change this to an ajax form so that the results displays on submit instead without altering any mark-up? Pulling the results (mark-up) from the results page back to the form page.
我正在使用一种我无法更改标记且无法使用 jQuery 的表单。目前,表单将结果发布到新窗口。是否可以将其更改为 ajax 表单,以便在提交时显示结果而不更改任何标记?将结果(标记)从结果页面拉回表单页面。
Here is the mark-up for the form.
这是表单的标记。
<form class="form-poll" id="poll-1225962377536" action="/cs/Satellite" target="_blank">
<div class="form-item">
<fieldset class="form-radio-group">
<legend><span class="legend-text">What mobile phone is the best?</span></legend>
<div class="form-radio-item">
<input type="radio" class="radio" value="1225962377541" name="option" id="form-item-1225962377541">
<label class="radio" for="form-item-1225962377541">
<span class="label-text">iPhone</span>
</label>
</div><!-- // .form-radio-item -->
<div class="form-radio-item">
<input type="radio" class="radio" value="1225962377542" name="option" id="form-item-1225962377542">
<label class="radio" for="form-item-1225962377542">
<span class="label-text">Android</span>
</label>
</div><!-- // .form-radio-item -->
<div class="form-radio-item">
<input type="radio" class="radio" value="1225962377543" name="option" id="form-item-1225962377543">
<label class="radio" for="form-item-1225962377543">
<span class="label-text">Symbian</span>
</label>
</div><!-- // .form-radio-item -->
<div class="form-radio-item">
<input type="radio" class="radio" value="1225962377544" name="option" id="form-item-1225962377544">
<label class="radio" for="form-item-1225962377544">
<span class="label-text">Other</span>
</label>
</div><!-- // .form-radio-item -->
</fieldset>
</div><!-- // .form-item -->
<div class="form-item form-item-submit">
<button class="button-submit" type="submit"><span>Vote now</span></button>
</div><!-- // .form-item -->
<input type="hidden" name="c" value="News_Poll">
<input type="hidden" class="pollId" name="cid" value="1225962377536">
<input type="hidden" name="pagename" value="Foundation/News_Poll/saveResult">
<input type="hidden" name="site" value="themouth">
Any tips/tutorial is much appreciated. :)
非常感谢任何提示/教程。:)
回答by Madara's Ghost
The following is a far more elegant solution of the other answer, more fit for modern browsers.
以下是另一个答案的更优雅的解决方案,更适合现代浏览器。
My reasoning is that if you need support for older browser you already most likely use a library like jQuery, and thus making this question pointless.
我的理由是,如果您需要对旧浏览器的支持,您很可能已经使用了 jQuery 之类的库,因此这个问题毫无意义。
/**
* Takes a form node and sends it over AJAX.
* @param {HTMLFormElement} form - Form node to send
* @param {function} callback - Function to handle onload.
* this variable will be bound correctly.
*/
function ajaxPost (form, callback) {
var url = form.action,
xhr = new XMLHttpRequest();
//This is a bit tricky, [].fn.call(form.elements, ...) allows us to call .fn
//on the form's elements, even though it's not an array. Effectively
//Filtering all of the fields on the form
var params = [].filter.call(form.elements, function(el) {
//Allow only elements that don't have the 'checked' property
//Or those who have it, and it's checked for them.
return typeof(el.checked) === 'undefined' || el.checked;
//Practically, filter out checkboxes/radios which aren't checekd.
})
.filter(function(el) { return !!el.name; }) //Nameless elements die.
.filter(function(el) { return el.disabled; }) //Disabled elements die.
.map(function(el) {
//Map each field into a name=value string, make sure to properly escape!
return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
}).join('&'); //Then join all the strings by &
xhr.open("POST", url);
// Changed from application/x-form-urlencoded to application/x-form-urlencoded
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//.bind ensures that this inside of the function is the XHR object.
xhr.onload = callback.bind(xhr);
//All preperations are clear, send the request!
xhr.send(params);
}
The above is supported in all major browsers, and IE9 and above.
以上支持所有主流浏览器,IE9及以上。
回答by Coomie
Here's a nifty function I use to do exactly what you're trying to do:
这是我用来做你想做的事情的一个漂亮的函数:
HTML:
HTML:
<form action="/cs/Satellite">...</form>
<input type="button" value="Vote now" onclick="javascript:AJAXPost(this)">
JS:
JS:
function AJAXPost(myself) {
var elem = myself.form.elements;
var url = myself.form.action;
var params = "";
var value;
for (var i = 0; i < elem.length; i++) {
if (elem[i].tagName == "SELECT") {
value = elem[i].options[elem[i].selectedIndex].value;
} else {
value = elem[i].value;
}
params += elem[i].name + "=" + encodeURIComponent(value) + "&";
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST",url,false);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setRequestHeader("Content-length", params.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(params);
return xmlhttp.responseText;
}
回答by ZachB
Nowadays using FormData
is the easiest method. You construct it with a reference to the Form
element, and it serializes everything for you.
现在使用FormData
是最简单的方法。您使用对Form
元素的引用来构造它,它会为您序列化所有内容。
MDN has an example of this here-- roughly:
MDN在这里有一个例子——大致如下:
const form = document.querySelector("#debarcode-form");
form.addEventListener("submit", e => {
e.preventDefault();
const fd = new FormData(form);
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", e => {
console.log(e.target.responseText);
});
xhr.addEventListener("error", e => {
console.log(e);
});
xhr.open("POST", form.action);
xhr.send(fd);
});
and if you want it as an object (JSON):
如果你想把它作为一个对象(JSON):
const obj = {};
[...fd.entries()].forEach(entry => obj[entry[0]] = entry[1]);
回答by Vince
Expanding on Madara's answer: I had to make some changes to make it work on Chrome 47.0.2526.80 (not tested on anything else). Hopefully this can save someone some time.
扩展 Madara 的回答:我必须进行一些更改才能使其在 Chrome 47.0.2526.80 上运行(未在其他任何设备上进行测试)。希望这可以节省一些时间。
This snippet is a modification of that answer with the following changes:
此代码段是对该答案的修改,并进行了以下更改:
- filter
!el.disabled
, - check type of input before excluding
!checked
- Request type to
x-www-form-urlencoded
- 过滤器
!el.disabled
, - 在排除之前检查输入类型
!checked
- 请求类型为
x-www-form-urlencoded
With the following result:
结果如下:
function ajaxSubmit(form, callback) {
var xhr = new XMLHttpRequest();
var params = [].filter.call(form.elements, function (el) {return !(el.type in ['checkbox', 'radio']) || el.checked;})
.filter(function(el) { return !!el.name; }) //Nameless elements die.
.filter(function(el) { return !el.disabled; }) //Disabled elements die.
.map(function(el) {
return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
}).join('&'); //Then join all the strings by &
xhr.open("POST", form.action);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onload = callback.bind(xhr);
xhr.send(params);
};
回答by RobG
The strategy is to serialise the form and send the data using XHR, then do what you want with the response. There is a good set of utilities and help at Matt Krus's Ajax Toolboxand related Javascript Toolbox.
策略是序列化表单并使用 XHR 发送数据,然后对响应执行您想要的操作。在 Matt Krus 的Ajax Toolbox和相关的Javascript Toolbox 中有一组很好的实用程序和帮助。
If you are just serialising the form posted, then the following will do the trick. It can easily be extended to include other form control types:
如果您只是对发布的表单进行序列化,那么以下内容就可以解决问题。它可以很容易地扩展到包括其他表单控件类型:
var serialiseForm = (function() {
// Checkboxes that have already been dealt with
var cbNames;
// Return the value of a checkbox group if any are checked
// Otherwise return empty string
function getCheckboxValue(cb) {
var buttons = cb.form[cb.name];
if (buttons.length) {
for (var i=0, iLen=buttons.length; i<iLen; i++) {
if (buttons[i].checked) {
return buttons[i].value;
}
}
} else {
if (buttons.checked) {
return buttons.value;
}
}
return '';
}
return function (form) {
var element, elements = form.elements;
var result = [];
var type;
var value = '';
cbNames = {};
for (var i=0, iLen=elements.length; i<iLen; i++) {
element = elements[i];
type = element.type;
// Only named, enabled controls are successful
// Only get radio buttons once
if (element.name && !element.disabled && !(element.name in cbNames)) {
if (type == 'text' || type == 'hidden') {
value = element.value;
} else if (type == 'radio') {
cbNames[element.name] = element.name;
value = getCheckboxValue(element);
}
}
if (value) {
result.push(element.name + '=' + encodeURIComponent(value));
}
value = '';
}
return '?' + result.join('&');
}
}());
回答by ferdynator
A modern way using fetch
would be:
一种现代的使用fetch
方式是:
const formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData
});
Note browser supportand use this polyfilif IE-support is needed
回答by bLight
Here's the simplest method I came up with. I haven't found an example that uses this exact approach. The code submits the form using a non-submit type button and places the results into a div, if the form is not valid (not all required fields filled), it will ignore the submit action and the browser itself will show which fields are not filled correctly.
这是我想出的最简单的方法。我还没有找到使用这种确切方法的示例。代码使用非提交类型按钮提交表单并将结果放入 div 中,如果表单无效(未填写所有必填字段),它将忽略提交操作,浏览器本身将显示哪些字段不是正确填写。
This code only works on modern browsers supporting the "FormData" object.
此代码仅适用于支持“FormData”对象的现代浏览器。
<script>
function ajaxSubmitForm() {
const form = document.getElementById( "MyForm" );
if (form.reportValidity()) {
const FD = new FormData( form );
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("content_area").innerHTML = this.responseText; } };
xhttp.open("POST","https://example.com/whatever.php",true);
xhttp.send( FD );
}
}
</script>
<div id="content_area">
<form id="MyForm">
<input type="hidden" name="Token" Value="abcdefg">
<input type="text" name="UserName" Value="John Smith" required>
<input type="file" accept="image/jpeg" id="image_uploads" name="ImageUpload" required>
<button type="button" onclick="ajaxSubmitForm()">
</form>
</div>
回答by Brandan
function ajaxSubmit(form, callback) {
var xhr = new XMLHttpRequest();
var params = [].filter.call(form.elements, function (el) {return !(el.type in ['checkbox', 'radio']) || el.checked;})
.filter(function(el) { return !!el.name; }) //Nameless elements die.
.filter(function(el) { return !el.disabled; }) //Disabled elements die.
.map(function(el) {
if (el.type=='checkbox') return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.checked);
else return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
}).join('&'); //Then join all the strings by &
xhr.open("POST", form.action);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onload = callback.bind(xhr);
xhr.send(params);
};
};
回答by Seth
I just took Coomie's answer above and made it work for Radio/Checkboxes. I can't believe how simple and clear this is. With a few exceptions, I'm done using frameworks.
我刚刚接受了上面 Coomie 的回答,并使其适用于 Radio/Checkboxes。我无法相信这是多么简单和清晰。除了少数例外,我已经使用了框架。
var params = "";
var form_elements = form.elements;
for (var i = 0; i < form_elements.length; i++)
{
switch(form_elements[i].type)
{
case "select-one":
{
value = form_elements[i].options[form_elements[i].selectedIndex].value;
}break;
case "checkbox":
case "radio":
{
if (!form_elements[i].checked)
{
continue; // we don't want unchecked data
}
value = form_elements[i].value;
}break;
case "text" :
{
value = form_elements[i].value;
}break;
}
params += encodeURIComponent(form_elements[i].name) + "=" + encodeURIComponent(value) + "&";
}
var xhr = new XMLHttpRequest();
xhr.open('POST', "/api/some_url");
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200)
{
console.log("xhr.responseText");
}
else
{
console.log("Error! Status: ", xhr.status, "Text:", xhr.responseText);
}
}
};
console.log(params);
xhr.send(params);