如何在用户提交无效输入后重新加载谷歌验证码小部件

35

我有一个带有新的 Google reCAPTCHA 部件的注册表单。当用户提交信息时,我们使用 JavaScript 进行验证并将问题返回给页面(例如:“请使用有效的电话号码”)。但是,由于页面不重新加载,当用户输入正确信息并再次提交(无需再次进行 reCAPTCHA)时...reCAPTCHA 不再有效,他们不能在不重新加载页面的情况下提交。

是否有好的解决方案?我能否以某种方式重新加载该部件?我尝试过 grecaptcha.render 但它并没有真正做任何事情。

编辑:

当我尝试重新渲染该部件时,它会显示“占位符元素必须为空”

我尝试清空该元素似乎可以工作 ($('.g-recaptcha').empty();),然后进行渲染,但仍会引发相同的错误。


你能展示一下你调用脚本的方式吗? - Ghislaindj
11个回答

43

你需要的方法是grecaptcha.reset()

不过,在使用这个函数之前,你必须显式地呈现reCaptacha,如下所示:<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>


4
我使用这个方法时出现了一个错误:无效的 ReCAPTCHA 客户端 ID:undefined。 - Oleg Abrazhaev
3
作为附加说明 - 如果您想重置特定的reCAPTCHA(在单个页面上有多个reCAPTCHA的情况下),您可以通过应用每个验证码的变量名称来这样做,例如grecaptcha.reset(captcha1) - jshbrmn
1
如果更改onload函数的名称,您会收到一个错误“TypeError:a为null”。为什么?他们是否假定reset()上的onload函数是onloadCallback - Sean Kendle
4
如果这些信息在官方的Google文档中就更好了,但实际上并没有。而且在Google文档中没有提供反馈选项,这真是令人遗憾。 - PromInc
onloadCallback函数的定义是什么?抱歉,我对JavaScript不太熟悉。 - Farhad

10
我能够只使用以下方法来完成这个任务:

grecaptcha.reset();

as simple as that, tks! - Pedro Lobito

8
如果您在使用jQuery进行grecaptcha.render操作,请确保您实际上正在设置DOM元素,而不是jQuery元素:
这样做可以
grecaptcha.render( $('.g-recaptcha')[0], { sitekey : 'your_key_here' });

但这样不会起作用:

grecaptcha.render( $('.g-recaptcha'), { sitekey : 'your_key_here' });

8

个人而言,我通过以下方式重设我的 HTML 元素内容:

$('#captcha').html('');

之后,我使用以下代码重新加载reCAPTCHA:
$.getScript("https://www.google.com/recaptcha/api.js");

在您的网站上加载reCAPTCHA内容。
<div id="captcha" class="g-recaptcha" data-sitekey="yourSitePublicKey"></div>

使用reset方法更好,但如果您需要在页面上重置已自动呈现的recaptcha,并且有多个小部件,则将inner html设置为空即可解决问题。 (+1) - Jarda

7
这里是一些代码,配合@tzafar的答案使用:
var myCaptcha = null;
function prepCaptcha() {
    if (myCaptcha === null)
        myCaptcha = grecaptcha.render(document.getElementById('my-captcha'), {
            'sitekey': myCaptchaKey,
            'theme': 'light'
        });
    else
        grecaptcha.reset(myCaptcha);
}

在我的情况下,my-captcha 是 Bootstrap 模态框内 div 的 id。我在模态框的 shown.bs.modal 事件处理程序中运行 prepCaptcha()。第一次,它会初始化验证码。在模态框的后续显示中,它将重置验证码。
此外,请注意,您可以通过打印完成的验证码值来快速验证是否获得了新的验证码:
console.log(grecaptcha.getResponse(myCaptcha));

您不应该看到两次相同的值。


非常奇怪,在一个网站上我用这种方式它是可以工作的:grecaptcha.render('RecaptchaField1', {'sitekey' : 'mySiteKey'}); 但在另一个网站上它却不起作用,我不得不使用你的方式:grecaptcha.render(document.getElementById('RecaptchaField1'), {'sitekey' : 'mySiteKey'}); - ivva
你们节省了我的时间,谢谢。 - funbrain9

3
您的验证码渲染js事件应该只在脚本中调用一次,如果在脚本中第二次调用grecaptcha.render js事件,则您的验证码代码无效。您应该检查您的代码,以便在验证检查时不要第二次调用grecaptcha.render函数。
或者
在控制台中,您将看到一个“未捕获的引用错误:Recaptcha未定义”的错误消息,这表明reCAPTCHA脚本存在问题。这是由于页面中的url错误 - http://api.recaptcha.net/js/recaptcha_ajax.js。Google已更新reCAPTCHA并将脚本位置移动到http://www.google.com/recaptcha/api/js/recaptcha_ajax.js。
还要检查此帖子。

http://www.instructables.com/id/Fix-reCAPTCHA-errors-on-Instructables/

这篇文章中的内容是:

未捕获的引用错误:Recaptcha未定义


1
我实际上并没有渲染两次。我只渲染一次,但当我提交表单并收到422错误(因为另一个字段不正确)时,当我尝试使用有效字段再次提交时,它会说reCAPTCHA不正确。 - Matthew Berman

1
如果您使用WordPress,请确保没有安装其他reCaptcha插件...这是我的问题所在。

我没想到会是这样,但这就是我的情况。 - zawhtut

0
<script>
function cform(token) {
$.ajax({
type: 'POST',
url: 'contact_chk.php',
data: $('#cform').serialize(), 
success: function(response) {
grecaptcha.reset();
$("#con_msg").html(response);
document.getElementById("name").value='';
document.getElementById("subject").value='';
document.getElementById("email").value='';
document.getElementById("phone").value='';
document.getElementById("message").value='';
},
error: function(response) {
grecaptcha.reset();
$("#con_msg").html('Try Again...');
}
});
}
</script>
<script src='https://www.google.com/recaptcha/api.js'></script>

0
如果您正在使用新的reCAPTCHA 2.0,请使用以下代码: 对于后端代码:
ScriptManager.RegisterStartupScript(this, this.GetType(), "CaptchaReload", "$.getScript(\"https://www.google.com/recaptcha/api.js\", function () {});", true);

对于简单的JavaScript

<script>$.getScript(\"https://www.google.com/recaptcha/api.js\", function () {});</script>

0

每当我尝试从控制台执行此操作时,它会显示“Recaptcha不是函数”。我做错了吗? - Matthew Berman
@JeremyF。好的,感谢你在一年后对更新进行了负面评价... 为什么有人会回答,当它在以后的日期被弃用时,只是为了让别人来给他们一个负面的评论呢? - StaticVoid
@StaticVoid,我之所以没有将答案排在列表的前面,是因为我认为对于当前用户来说,这个答案并不是那么相关。此外,如果没有我的评论,一些不了解版本差异的人可能会一眼看不出哪个是哪个。当我搜索这个问题时,我也遇到了同样的情况。 抱歉,我并不是有意冒犯你! - Jeremy F.
@JeremyF。不会有任何冒犯的意思。我只是认为因为新版本发布了就去逐个点踩网站上的所有内容是多余的...继续做你自己的事吧。 - StaticVoid

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