Ember中g-recaptcha组件刷新路由后无法渲染问题求助
解决Ember g-recaptcha组件刷新/直接访问路由时无法渲染的问题
我之前也遇到过完全一样的Ember reCAPTCHA组件问题,咱们来拆解一下原因和解决方案:
问题核心原因
当你直接刷新路由或者首次访问路由时,Google reCAPTCHA的异步脚本还没加载完成,你的组件就已经尝试调用window.grecaptcha.render方法了——这就是控制台报错Uncaught TypeError: window.grecaptcha.render is not a function的根源。而通过{{#link-to}}跳转时,脚本已经在之前的页面加载完毕,所以组件能正常初始化和渲染。
具体解决方案
1. 在路由层面提前加载reCAPTCHA脚本
最稳妥的方式是在进入目标路由前,确保脚本已经加载完成。可以在路由的beforeModel钩子中添加脚本加载逻辑:
// app/routes/your-target-route.js import Route from '@ember/routing/route'; export default class YourTargetRoute extends Route { async beforeModel() { // 等待reCAPTCHA脚本加载完成再进入路由 await this._loadRecaptchaScript(); } _loadRecaptchaScript() { return new Promise((resolve, reject) => { // 如果脚本已经加载,直接resolve if (window.grecaptcha) { resolve(); return; } const script = document.createElement('script'); // 替换成你的sitekey,或者保持explicit模式 script.src = 'https://www.google.com/recaptcha/api.js?render=explicit'; script.async = true; script.defer = true; script.onload = resolve; script.onerror = () => reject(new Error('Failed to load reCAPTCHA script')); document.body.appendChild(script); }); } }
这样组件渲染时,window.grecaptcha肯定已经存在,不会出现找不到方法的错误。
2. 在组件内部添加加载检测逻辑
如果不想在路由层面处理,也可以在组件内部做延迟渲染,等待脚本加载完成:
// app/components/g-recaptcha.js import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; export default class GRecaptchaComponent extends Component { @tracked isRecaptchaReady = false; constructor() { super(...arguments); this._waitForRecaptcha(); } _waitForRecaptcha() { // 立即检查一次 if (window.grecaptcha) { this.isRecaptchaReady = true; this._renderCaptcha(); return; } // 轮询检测脚本加载状态,间隔可以根据需要调整 const checkInterval = setInterval(() => { if (window.grecaptcha) { clearInterval(checkInterval); this.isRecaptchaReady = true; this._renderCaptcha(); } }, 150); } _renderCaptcha() { window.grecaptcha.render(this.element, { sitekey: this.args.sitekey, // 这里添加你的其他reCAPTCHA配置,比如theme、size等 }); } }
然后在组件模板中,只有当脚本准备好后才渲染容器:
{{#if this.isRecaptchaReady}} <div class="g-recaptcha-container"></div> {{/if}}
3. 排查组件渲染阻塞问题
从Ember Inspector看到组件未被渲染,大概率是脚本加载失败导致组件初始化抛出错误,进而被Ember的错误处理机制阻止渲染。解决脚本加载时机后,这个问题应该会自动消失。另外可以检查组件模板中有没有条件渲染逻辑(比如{{#if}})意外阻止了组件显示。
内容的提问来源于stack exchange,提问作者El Poisen
相关产品推荐
相关产品推荐

