问题描述
当前我使用的是聚合物版本3.0,我尝试实现recaptcha v2,但是加载脚本存在问题:<script src="https://www.google.com/recaptcha/api.js" async defer></script>
,聚合物无法在阴影dom内加载脚本。我在这里找到了用于验证码的Web组件:https://www.webcomponents.org/element/Zecat/google-recaptcha,但这仅支持聚合物的版本1和2.x。有没有一种方法可以在聚合物3.0中实现recaptcha(checkBox)?
解决方法
我发现的技巧是在运行时创建必要的脚本标签并将脚本附加到文档头部或正文以显示 reCAPTCHA 元素。在 firstUpdated() 方法上执行此操作,请执行以下步骤:
1: 为 google recaptcha api 创建脚本标签
var script = document.createElement( 'script' );
script.src= 'https://www.google.com/recaptcha/api.js';
script.async = true;
script.defer = true;
-
将脚本附加到文档头
document.head.appendChild(script);
-
创建 div 以在运行时托管 reCAPTCHA 并将其附加到正文,因为它不会显示在 shadowRoot 上
var recaptcha = document.createElement('div');
recaptcha.setAttribute('class','g-recaptcha');
recaptcha.setAttribute('data-theme','light');
recaptcha.setAttribute('data-callback','recaptchaCallback');
recaptcha.setAttribute('data-sitekey','site_key');
//attaching recaptcha element to document body
document.body.appendChild(recaptcha);
此时,recaptcha 元素将显示在文档上。但唯一的问题将是它在哪里的位置。所以这里的问题是如何将它显示到 shdadowRoot 在 DOM 上加载的位置。对此的技巧是在运行时获取 shadowRoot 的位置,并将样式属性附加到我们刚刚创建的 recaptcha div,我们将位置设置为 absoulte postion:absolute
并添加底部和左侧位置基于shadowRoot 所在的位置。它看起来像这样:
let rBody =this.shadowRoot.querySelector("#rBody"); //element in the shadowRoot
let topPosition = rBody.getBoundingClientRect().top;
let leftPosition = rBody.getBoundingClientRect().left;
recaptcha.setAttribute('style','position:absolute;top:'+ topPosition+ 'px;'+ 'left:'+ leftPosition + 'px;');
此时,recaptcha 应该相应地定位自己。希望您使用的表单没有动画,因为 recaptcha 将始终保持原位,但它可以工作。
所以另一个关键因素是知道 recaptcha 的验证是否成功。我们还必须为此做另一个黑客攻击。为此,我们还在运行时创建了一个脚本标记,它的文本内容嵌入了一个函数,该函数将被 google 的 data-callback 属性调用。回调函数仅在成功时才被调用,这对我们来说已经足够了。有关详细信息,请查看文档 here 它应该如下所示:
recaptcha.setAttribute('data-callback','recaptchaCallback');
//script for callback
let callBackScript = document.createElement( 'script' );
callBackScript.textContent = ' function recaptchaCallback(){var recapValue = document.createElement("p"); recapValue.setAttribute("id","recapValue"); recapValue.setAttribute("pass","r-true");document.body.appendChild(recapValue);console.log("Recaptcha callback passed");}';
document.body.appendChild(callBackScript);
回调函数我还创建了一个 p
元素并设置了一个自定义属性,如果元素被实际创建,则意味着验证成功,您可以通过创建一个方法来确认创建的元素,在这种情况下 p
如果它在 dom 上:
let recaptchaValue = document.querySelector('#recapValue');
if(recaptchaValue !=null){
return recaptchaValue.getAttribute("pass");
}else{
return null;
}
希望这能帮到你。不幸的是,对于 Polymer 3.0,我们不得不求助于这些 hack,因为我们的特定用例没有节点包。