javascript - 是否有任何 recaptcha v2 关闭事件?

标签 javascript recaptcha

我正在用这样的代码渲染 grecaptcha

let callback;
const p = new Promise((resolve) => callback = (result) => resolve(result));

grecaptcha.render(el, {
    sitekey: window.settings.recaptchaKey,
    size: "invisible",
    type: "image",
    callback: result => callback(result),
    badge: "inline"
});

const key = await p;

一切正常,但如果用户点击 recaptcha 模式的背景,recaptcha 关闭并且我无法检测到它,所以我无限等待响应

我需要某种事件或回调来检测它何时关闭

最佳答案

不幸的是,Google 没有 API 事件来跟踪这个,但我们可以使用 Mutation Observer用于通过我们自己的 Google API 跟踪 DOM 更改的 Web API。

我们在这里有 2 个挑战。

1) 检测挑战何时显示并获取挑战的覆盖 div

function detectWhenReCaptchaChallengeIsShown() {
    return new Promise(function(resolve) {
        const targetElement = document.body;

        const observerConfig = {
            childList: true,
            attributes: false,
            attributeOldValue: false,
            characterData: false,
            characterDataOldValue: false,
            subtree: false
        };

        function DOMChangeCallbackFunction(mutationRecords) {
            mutationRecords.forEach((mutationRecord) => {
                if (mutationRecord.addedNodes.length) {
                    var reCaptchaParentContainer = mutationRecord.addedNodes[0];
                    var reCaptchaIframe = reCaptchaParentContainer.querySelectorAll('iframe[title*="recaptcha"]');

                    if (reCaptchaIframe.length) {
                        var reCaptchaChallengeOverlayDiv = reCaptchaParentContainer.firstChild;
                        if (reCaptchaChallengeOverlayDiv.length) {
                            reCaptchaObserver.disconnect();
                            resolve(reCaptchaChallengeOverlayDiv);
                        }
                    }
                }
            });
        }

        const reCaptchaObserver = new MutationObserver(DOMChangeCallbackFunction);
        reCaptchaObserver.observe(targetElement, observerConfig);
    });
}

首先,我们创建了一个目标元素,用于观察 Google iframe 的外观。我们以 document.body 为目标,因为 iframe 将附加到它:

const targetElement = document.body;

然后我们为 MutationObserver 创建了一个配置对象。在这里,我们可能会指定我们在 DOM 更改中准确跟踪的内容。请注意,默认情况下所有值都是“false”,所以我们只能保留“childList”——这意味着我们只会观察目标元素的子节点变化——在我们的例子中是 document.body:

const observerConfig = {
    childList: true,
    attributes: false,
    attributeOldValue: false,
    characterData: false,
    characterDataOldValue: false,
    subtree: false
};

然后我们创建了一个函数,当观察者检测到我们在配置对象中指定的特定类型的 DOM 更改时将调用该函数。第一个参数表示 Mutation Observer 的数组对象。我们抓取覆盖 div 并返回 Promise。

function DOMChangeCallbackFunction(mutationRecords) {
    mutationRecords.forEach((mutationRecord) => {
        if (mutationRecord.addedNodes.length) { //check only when notes were added to DOM
            var reCaptchaParentContainer = mutationRecord.addedNodes[0];
            var reCaptchaIframe = reCaptchaParentContainer.querySelectorAll('iframe[title*="recaptcha"]');

            if (reCaptchaIframe.length) { // Google reCaptcha iframe was loaded
                var reCaptchaChallengeOverlayDiv = reCaptchaParentContainer.firstChild;
                if (reCaptchaChallengeOverlayDiv.length) {
                    reCaptchaObserver.disconnect(); // We don't want to observe more DOM changes for better performance
                    resolve(reCaptchaChallengeOverlayDiv); // Returning the overlay div to detect close events
                }
            }
        }
    });
}

最后我们实例化了一个观察者本身并开始观察 DOM 变化:

const reCaptchaObserver = new MutationObserver(DOMChangeCallbackFunction);
reCaptchaObserver.observe(targetElement, observerConfig);

2) 第二个挑战是该帖子的主要问题 - 我们如何检测到挑战已结束?那么,我们再次需要 MutationObserver 的帮助。

detectReCaptchaChallengeAppearance().then(function (reCaptchaChallengeOverlayDiv) {
    var reCaptchaChallengeClosureObserver = new MutationObserver(function () {
        if ((reCaptchaChallengeOverlayDiv.style.visibility === 'hidden') && !grecaptcha.getResponse()) {
            // TADA!! Do something here as the challenge was either closed by hitting outside of an overlay div OR by pressing ESC key
            reCaptchaChallengeClosureObserver.disconnect();
        }
    });
    reCaptchaChallengeClosureObserver.observe(reCaptchaChallengeOverlayDiv, {
        attributes: true,
        attributeFilter: ['style']
    });
});

因此,我们所做的是使用我们在步骤 1 中创建的 Promise 获得 Google reCaptcha 挑战覆盖 div,然后我们订阅覆盖 div 上的“样式”更改。这是因为当挑战结束时 - 谷歌将其淡出。 重要的是要注意,当一个人成功解决了验证码时,可见性也会被隐藏。这就是我们添加 !grecaptcha.getResponse() 检查的原因。除非挑战得到解决,否则它不会返回任何内容。 差不多就是这些 - 希望对您有所帮助 :)

关于javascript - 是否有任何 recaptcha v2 关闭事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44571782/

相关文章:

javascript - 找到总和为目标值的所有对

javascript - 如何在鼠标悬停时显示特定 div 的元素

javascript - 如何在使用 useCallback 时内存高阶函数?

javascript - 要求用户在提交表单之前点击谷歌的新验证码

ruby-on-rails - ROR 中的验证码实现

javascript - ...scrollTop($(这个)...)

javascript - 从 .csv 中提取的变量不会添加

ReCaptcha NoCaptcha 始终显示 Firefox 的额外验证

asp.net - 如何在 MVC3 应用程序中实现 Google reCaptcha?

php - google recaptcha 响应为空 [PHP, localhost]