如何在HTML5验证通过后运行reCaptcha?

34
通常情况下,HTML5表单验证在submit事件之前运行。

使用这个
<form id="myForm">
    <input  type="text" name="foo" required />

    <button type="submit"> Submit </button>

</form>

<script>
    $("#myForm").on('submit',function(){
        console.log("I'm entering the submit event handler");
    });
</script>

如果输入字段为空,则提交事件处理程序不会运行。只有在HTML5验证(在这种情况下为required属性)通过后才会触发。
我希望验证码在HTML5验证之后运行; 如果稍后我会警告用户有缺失的字段,为什么要编译验证码来打扰用户? 我认为首先应该强制用户按正确的方式操作,然后再确保它是人类而不是机器。
显然,reCaptcha对其附加的表单进行了某些操作,从而删除了HTML5验证功能。
例如,使用最新的Invisible reCaptcha
<form id="myForm">
    <input  type="text" name="foo" required />

    <button type="submit"
           class="g-recaptcha" 
    data-sitekey="your_site_key" 
   data-callback='myCallback'> Submit </button>

</form>

<script>
    function myCallback(token){
        $("#myForm").submit();
    }

    $("#myForm").on('submit',function(){
        console.log("I'm entering the submit event handler");
    });
</script>

表格将被提交,其中包含空字段,而不通知用户其必要性。
你有什么线索可以解释为什么会出现这种情况吗?我能否指示reCaptcha在接管之前运行HTML5表单验证?
3个回答

54

不要直接将reCAPTCHA属性附加到按钮上,而是必须将它们添加到一个div中,然后在提交表单时使用grecaptcha.execute();

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

<form id="myForm">
    Name: (required) <input id="field" name="field" required>
    <div id='recaptcha' class="g-recaptcha"
         data-sitekey="your_site_key"
         data-callback="onCompleted"
         data-size="invisible"></div>
    <button id='submit'>submit</button>
</form>
<script>
    $('#myForm').submit(function(event) {
        console.log('validation completed.');

        event.preventDefault(); //prevent form submit before captcha is completed
        grecaptcha.execute();
    });

    onCompleted = function() {
        console.log('captcha completed.');
    }
</script>
当您像这样将reCAPTCHA属性添加到按钮中时,Google只需向按钮添加一个单击监听器,并在单击按钮时执行reCAPTCHA。不会添加提交监听器。 HTML5验证仅在单击提交按钮时触发,并在提交事件之前运行。这就是为什么我们必须确保reCAPTCHA在提交事件之后运行。显然,reCAPTCHA订阅的单击事件会在内部HTML5验证触发之前处理。当您使用submit()提交表单时,验证也不会被触发。这就是该函数的定义方式。因为您在回调中调用该函数,所以不会触发验证。但是即使您没有在回调中调用submit()函数,似乎reCAPTCHA也会停止事件的默认行为,从而完全停止验证。
在reCAPTCHA完成后提交表单
如果您希望在reCAPTCHA完成后提交表单,可以检查grecaptcha.getResponse()的结果。
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

<form id="myForm">
    Name: (required) <input id="field" name="field" required>
    <div id='recaptcha' class="g-recaptcha"
         data-sitekey="your_site_key"
         data-callback="onCompleted"
         data-size="invisible"></div>
    <input type="submit" value="submit" />
</form>
<script>
    $('#myForm').submit(function(event) {
        console.log('form submitted.');

        if (!grecaptcha.getResponse()) {
            console.log('captcha not yet completed.');

            event.preventDefault(); //prevent form submit
            grecaptcha.execute();
        } else {
            console.log('form really submitted.');
        }
    });

    onCompleted = function() {
        console.log('captcha completed.');
        $('#myForm').submit();
        alert('wait to check for "captcha completed" in the console.');
    }
</script>

非常整洁的答案!我仍然不知道为什么将事件附加到 onClick 处理程序会影响 onSubmit 处理程序,使其失去内置的验证功能,但这只是一个小问题:我的需求相当复杂(这只是谜题的第一部分),现在它们完全可以工作了。谢谢! - Andrea Ligios
我编辑了答案,以更好地回应你在帖子中提出的问题。不用谢! - maechler
感谢您的澄清,非常感谢!请注意不要达到20次编辑(您已经进行了11次),否则帖子将被转换为社区维基,并且您将失去所获得的声望 :) - Andrea Ligios
3
这个答案很棒,但是找起来很困难。 - amosmos
1
完美的解决方案,你救了我的夜晚! - Rustam Shafigullin
显示剩余4条评论

6
maechler的回答很好,但是如果不想使用jQuery,可以使用立即调用函数表达式添加事件监听器。
(function() {
    document.getElementById("my-form").addEventListener("submit", function(event) {
        console.log('form submitted.');
        if (!grecaptcha.getResponse()) {
            console.log('captcha not yet completed.');

            event.preventDefault(); //prevent form submit
            grecaptcha.execute();
        } else {
            console.log('form really submitted.');
        }
      });
  })();

我希望这有所帮助。

非常棒的补充,适用于非jQuery用户。但是缺少onCompleted函数。 - Berklie

0
将以下控件添加到表单中:
<input type="submit" id="reallySubmit" style="display:none" />

然后在Google脚本中的onSubmit事件处理程序中,不要submit表单,而是执行以下操作:
document.getElementById("reallySubmit").click();

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