我正在编写一个带有注册登录注销功能的简单网络应用程序作为练习任务。后端逻辑采用 PHP,客户端部分采用纯 HTML/CSS/Javascript。我被要求根据当前范围(注册或登录)动态生成注册/登录表单,因此我决定使用 Javascript 生成表单并发送表单数据(并接收验证错误消息)使用 AJAX 请求(JSON 格式)发送到服务器。
问题是生成表单时,自动触发 AJAX 请求,而无需单击“登录/注册”按钮。而且,发送 AJAX 请求的函数似乎无法获取输入来自输入字段的值,因此它仅发送范围。
每次重新生成表单时(因为范围已更改),它都会重新发送 AJAX 请求。
我已经尝试在单击“登录/注册”按钮时调用该函数,并仅在生成函数时将函数绑定(bind)到表单,但没有任何帮助。
以下是发送 AJAX 的函数:
function sendAjax(data) {
let xhr = new XMLHttpRequest();
xhr.open("POST", "process.php");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
let resData = JSON.parse(this.responseText);
Object.keys(resData).forEach(function (key) {
let e = resData[key];
if(document.getElementById(key+"span")!==null){
let div = document.getElementById(key+"G");
div.classList.add("has-error");
let span = document.getElementById(key+"span");
span.innerHTML = e;
}
});
}
};
xhr.send(data);
}
function process(scope) {
let inputs = document.getElementsByTagName("input");
console.log(inputs);
let filteredInputs = [];
for(let i = 0; i < inputs.length; i++){
if(inputs[i].type !== "submit"){
filteredInputs.push(inputs[i]);
}
}
console.log(filteredInputs);
let data = {scope: scope};
for(let i = 0; i < inputs.length; i++){
data[filteredInputs[i].name] = filteredInputs[i].value;
}
let dataJSON = JSON.stringify(data);
sendAjax(dataJSON);
return false;
}
这就是表单的生成方式:
let session = {
scope: "login",
setScope: function (scope) {
this.scope = scope;
document.getElementById("form-wrapper").appendChild(createForm(scope));
}
};
function createForm(scope){
if(document.getElementById("form")!==null){
let form = document.getElementById("form");
document.getElementById("form-wrapper").removeChild(form);
}
let form = document.createElement("form");
form.id = "form";
let buttons = document.createElement("div");
buttons.className = "form-group";
let title = document.createElement("h2");
if(scope === "login"){
title.innerHTML = "Bejelentkezés";
form.appendChild(title);
form.appendChild(createFormGroup("email"));
form.appendChild(createFormGroup("password"));
let login = document.createElement("input");
login.type = "submit";
login.className = "btn btn-primary";
login.value = "Bejelentkezés";
login.id = "btn-submit";
buttons.appendChild(login);
}
if(scope === "register"){
title.innerHTML = "Regisztráció";
form.appendChild(title);
formElementProps.forEach(((value, key) => form.appendChild(createFormGroup(key))));
let register = document.createElement("input");
register.type = "submit";
register.className = "btn btn-primary";
register.value = "Regisztráció";
register.id = "btn-submit";
let reset = document.createElement("input");
reset.type = "reset";
reset.className = "btn btn-deafult";
reset.value = "Törlés";
buttons.appendChild(register);
buttons.appendChild(reset);
}
let link = createLink(scope);
form.appendChild(buttons);
form.appendChild(link);
form.onsubmit = process(scope);
return form;
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById("form-wrapper").appendChild(createForm(session.scope));
});
后端逻辑看起来很好,因为当它自动触发时,它会响应正确的错误消息。
最佳答案
您的问题出在这一行:
form.onsubmit = process(scope);
这会将函数调用 process(scope)
的结果作为 form
的 onsubmit
属性传递。这当然没有任何意义,因为结果(返回值)是false
。但这确实意味着该函数被调用,从而在调用 createForm
函数时触发您的 Ajax。这正是您所提示的行为。
要解决这个问题,您可以记忆一下 form.onsubmit
像所有 HTML 属性一样,应该是一个“字符串”,在本例中是一个 JS 代码字符串,当提交事件时将对其进行评估发生。因此,这个看似微不足道的更改应该按预期工作(编辑:实际上不会,请参阅下面的评论):
form.onsubmit = "process(scope)";
但是,使用 HTML on***
属性来传递被评估为 JS 代码的字符串并不是很好的做法。更好的是使用 addEventListener 方法,并将应调用的实际函数传递给它。这里应该是:
form.addEventListener("submit", function() {
process(scope);
});
请注意,传递给 addEventListener
的第二个参数是一个函数 - 您可能会想要这样做
form.addEventListener("submit", process(scope));
但这会与您最初遇到的问题发生冲突 - process(scope)
将在遇到该行后立即执行,并且其返回值预计是一个函数(当然不是)。
关于javascript - 为什么当发送 AJAX req.js 的函数时,JS 生成的表单会在表单生成后立即触发 AJAX 请求。绑定(bind)到onsubmit事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57209731/