使用JavaScript的表单操作

50

我有一个表单,在提交时必须执行一个javascript函数,该函数然后将数据发布到我的php发件人邮件文件中并发送邮件。但是它只在火狐浏览器中起作用。在IE中,表单操作似乎没有起作用,我的问题是:这是从表单操作正确调用外部文件中的函数的方法吗?

action="javascript:simpleCart.checkout()"

simpleCart是一个.js文件,checkout()是其中的一个函数。

如果能提供一些提示就更好了,我很困惑为什么它可以在Firefox中运行,但在IE、Chrome或Safari中却不行。

<form name=form onsubmit="return validateFormOnSubmit(this)" enctype="multipart/form-data" action="javascript:simpleCart.checkout()" method="post">

你不能从 validateFormOnSubmit 函数中调用那个函数吗? - Joe
不行,因为simpleCart是我的购物车的巨大js文件,而validateFormOnSubmit来自我的验证.js文件,我无法将这些文件合并。 - whispering_Jack
我明白你的意思。我使用的方法不正确吗? - whispering_Jack
我已经在使用jQuery了,你能指导我正确的方向吗? - whispering_Jack
5个回答

58

绝对有效。

    <form action="javascript:alert('Hello there, I am being submitted');">
        <button type="submit">
            Let's do it
        </button>
    </form>
    <!-- Tested in Firefox, Chrome, Edge and Safari -->

所以简短回答:是的,这是一个选项,非常好用。它表示“当提交时,请不要离开,只需运行此脚本” - 直奔主题。 一个小的改进 为了让事件处理程序知道我们正在处理哪个表单,传递发送者对象似乎是一个显而易见的方法:
    <form action="javascript:myFunction(this)">  <!-- should work, but it won't -->

但是与其指向有意义的内容,this 将会指向 Window 对象。显然,javascript: 链接存在于不同的作用域中。因此,我建议使用以下格式,它只多了 13 个字符,但效果非常好:

    <form action="javascript:;" onsubmit="myFunction(this)">  <!-- now you have it! -->

现在您可以正确地访问发送者表单。(您可以将简单的“#”作为操作,这很常见 - 但它在提交时会产生滚动到顶部的副作用。)
再次强调,我喜欢这种方法,因为它是轻松和自我说明的。没有“返回false”,没有jQuery/domReady,没有重型武器。它只做它看起来要做的事情。当然,其他方法也可以工作,但对我来说,这是武士的方式。
关于验证的注释
仅当表单的onsubmit事件处理程序返回真值时,表单才会被提交,因此您可以轻松运行一些预先检查:
    <form action="/something.php" onsubmit="return isMyFormValid(this)">

现在 isMyFormValid 将首先运行,如果返回 false,则服务器甚至不会被打扰。毋庸置疑,您还必须在服务器端进行验证,这是更重要的验证。但为了快速方便地进行早期检测,这样做还是可以的。

古老的“打印此页面”void(0)可能是最安全、跨平台的方法,只要表单中有一个type="submit"的元素,就可以显示“Go”而不是“Return”键盘按钮。这是我为AngularJS应用程序提供的解决方案:<form name="login" action="javascript:void(0);" ng-submit="ctrl.login()"> - TaeKwonJoe
1
很奇怪(像 JavaScript 中的许多其他事情一样),"javascript:" 创建一个单独的作用域。那么,“this”又是什么呢?无论如何,这是一个优雅且实用的解决方案。恭喜! - alvaroc
@alvaroc 我相信这是 Window 对象。完全没有意义。 - dkellner
在 Chrome 中尝试过,是 Windows 系统,文章已相应更新。 - dkellner
不知道为什么“不被广泛支持”仍然是被接受的答案。 - dkellner

57

将表单的action设置为JavaScript函数并不被广泛支持,我很惊讶它在FireFox中能够工作。

最好的方法是将表单的action设置为你的PHP脚本;如果在提交之前需要进行任何操作,只需添加到onsubmit即可。

编辑:事实证明您不需要任何额外的函数,只需要在这里进行小小的更改:

function validateFormOnSubmit(theForm) {
    var reason = "";
    reason += validateName(theForm.name);
    reason += validatePhone(theForm.phone);
    reason += validateEmail(theForm.emaile);

    if (reason != "") {
        alert("Some fields need correction:\n" + reason);
    } else {
        simpleCart.checkout();
    }
    return false;
}

然后在您的表单中:

<form action="#" onsubmit="return validateFormOnSubmit(this);">

我把这个函数放在头部,像这样 `<script type=text/javascript>function validateAndSubmit(form) { if (validateFormOnSubmit(form)) { simpleCart.checkout(); } return false; } </script>` 但没有成功。 - whispering_Jack
你也更新了表格吗?如果是这样,出现了任何错误吗?使用调试器进行步骤处理等。 - Ja͢ck
这是我的提交按钮 <input type=submit name=Submit value=Send style=cursor:pointer /> - whispering_Jack
实际上它也没有验证。 - whispering_Jack
我对我的答案进行了更改,结果发现有一些双重功能是我们可以不需要的。我用IE9测试了表单,我没有看到任何问题。 - Ja͢ck
显示剩余8条评论

5
自问题被提出已经近8年了,但我想给出一个之前未曾提到过的答案。原帖作者说这个方法行不通:
action="javascript:simpleCart.checkout()"

楼主表示尝试所有好的建议后,这段代码仍然无法正常运行。因此我猜测问题可能出在这里:将checkout()作为simpleCart类的静态方法调用,但也有可能checkout()实际上是一个实例成员,而不是静态成员。这取决于他如何定义checkout()

顺便提一下,simpleCart很可能是一个类名,按照惯例,类名的首字母应该大写,所以我们在这里也采用这个约定。我们使用名称SimpleCart

以下是一些示例代码,演示如何将checkout()定义为实例成员。在ECMA-6之前,这是正确的方法:

function SimpleCart() {
    ...
}
SimpleCart.prototype.checkout = function() { ... };

许多人使用了一种不同的技术,如下所示。这种方法很流行,也很有效,但我不建议采用,因为实例应该只在原型上定义一次,而以下技术在每个实例上都重复定义成员变量,定义在this上。

function SimpleCart() {
    ...
    this.checkout = function() { ... };
}

以下是使用官方 class 在ECMA-6中定义 实例(instance) 的示例:

class SimpleCart {
    constructor() { ... }
    ...
    checkout()    { ... }
}

与ECMA-6中的静态定义相比,它们之间只有一个单词不同:

class SimpleCart {
    constructor() { ... }
    ...
    static checkout()    { ... }
}

这里是旧方法(ECMA-6之前)的静态定义。请注意,checkout()方法在函数外定义。它是函数对象的成员,而不是原型对象的成员,这就使它成为一个静态方法。

function SimpleCart() {
    ...
}
SimpleCart.checkout = function() { ... };

由于静态函数的定义方式不同,它对关键字 this 的引用会有不同的概念。请注意,实例 成员函数是使用关键字 this 调用的:
this.checkout();

静态成员函数使用类名调用:

SimpleCart.checkout();

问题在于OP想把调用放入HTML中,这将使其处于全局作用域中。他不能使用关键字this,因为this将引用全局作用域(即window)。
action="javascript:this.checkout()" // not as intended
action="javascript:window.checkout()" // same thing

在HTML中没有一种简单的方法可以使用实例成员函数。你可以利用JavaScript创建一个类的静态作用域内的注册表,并调用代理静态方法,同时将参数传递给代理使其给出实例在注册表中的索引,最后让代理调用实际的实例成员函数。类似这样:

// In Javascript:
SimpleCart.registry[1234] = new SimpleCart();

// In HTML
action="javascript:SimpleCart.checkout(1234);"

// In Javascript
SimpleCart.checkout = function(myIndex) {
    var myThis = SimpleCart.registry[myIndex];
    myThis.checkout();
}

你也可以将索引存储为元素的属性。
但通常在HTML中什么都不做,在JavaScript中使用.addEventListener()并使用.bind()能力会更容易。

1

我通常将js文件包含在html文档的头部,然后在操作中调用javascript函数。就像这样:

action="javascript:checkout()"

你试过这个吗?
别忘了在HTML头部引用脚本。
我不知道为什么它在Firefox中能工作。
谢谢。

我唯一能让它工作的方法是使用表单操作,但在IE浏览器中无法正常运行。我不明白为什么已经发布的解决方案不起作用,它们不会调用simpleCart.checkout函数。 - whispering_Jack
在我看来,最好的方法是使用jQuery。请查看以下链接:http://api.jquery.com/submit/ (提交事件)。以及这个基于Ajax的表单示例网页:http://www.queness.com/post/160/create-a-ajax-based-form-submission-with-jquery,该网页中提供有演示。 - vfabre

0
使用nextJS服务器操作(实验性功能)时,关于提交表单的一件事是它会将formData一起发送。如果您需要获取formData,这里是我从[MDN][1]找到的解决方案。然而,我还没有找到一种方法来告诉实验性的useFormState钩子,表单正在等待中,因此它将执行与提交相同的操作,但不会更新钩子提供的等待状态。
export default MyComponent(){
  const [state, formAction] = useFormState(submitFormAction, initialState)

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      e.preventDefault()
      handleSubmitForm()
    }
  }

  const handleSubmitForm = async () => {
    const formElement: HTMLFormElement | null = document.querySelector("form");
    const formData = new FormData(formElement || undefined);
    await formAction(formData)
  }

  return(
    <form action={formAction}
      ...
    </form>
  )

}

编辑: 在四处寻找之后,我发现只要在按下回车键时触发表单按钮,就可以使待处理的功能正常工作,这样会简单一些。
  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      e.preventDefault()
      triggerSubmitClick()
    }
  }

  const triggerSubmitClick = () => {
    const submitButton: HTMLButtonElement | null = document.querySelector("button[type='submit']");
    if (submitButton) {
      submitButton.click();
    }
  }

[1] https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接