清除 Vue 组件中 destroyed() 回调中的 mounted() 附加脚本

Clean-up mounted()-attached script in destroyed() callback in Vue component

我正在以编程方式将必要的脚本添加到我的一些 Vue 组件中,如下所示:

mounted() {
    const
        googleRecaptchaScript = document.createElement('script'),
        recaptchaURL = 'https://www.google.com/recaptcha/api.js';
    googleRecaptchaScript.setAttribute('src', recaptchaURL);
    googleRecaptchaScript.setAttribute('id', 'grecaptchascript');
    document.head.appendChild(googleRecaptchaScript);
},

现在,我注意到,如果我离开组件并返回到它,而不刷新页面,Vue 将开始加载我在 mounted() 调用中附加的内容的副本。所以我想按如下方式清理它们:

beforeDestroy() {
    const gsc = document.getElementById('grecaptchascript');
    gsc.parentElement.removeChild(gsc);
},

然而,该脚本的 id 似乎从未设置过,因此清理步骤无提示地失败了。

我做的完全错了吗?这样做有更好的模式吗?如果不是,为什么我的 <script> 没有得到我正在设置的 id

脚注:我知道在这里使用 id 是有问题的,因为我们正在谈论重复的元素。我稍后会更改它。如果有帮助,请考虑按任意属性进行选择的一般情况。我尝试了其他属性但没有成功。

我不确定问题到底是什么,但为了将来参考,此解决方案有效并且对我的情况来说似乎相当不错,因为它选择 scriptsrc 的前缀属性:

mounted() {
    const
        googleRecaptchaScript = document.createElement('script'),
        recaptchaURL = `https://www.google.com/recaptcha/api.js?hl=${this.$i18n.locale}`;
    googleRecaptchaScript.setAttribute('src', recaptchaURL);
    document.head.appendChild(googleRecaptchaScript);
},
beforeDestroy() {
    const recaptchaScripts = document.querySelectorAll('script[src^="https://www.google.com/recaptcha/api.js"]');
    for (let i = 0; i < recaptchaScripts.length; i += 1) {
        recaptchaScripts[i].parentElement.removeChild(recaptchaScripts[i]);
    }
},

我很确定 id 也能正常工作,我只是愚蠢。如果有人有更好的解决方案,我仍然很感兴趣,因为 "manually"(以编程方式)从页面中选择和删除元素似乎有点脏。

我认为这样的清理没有必要:加载脚本后,所有函数和变量的定义都落入全局范围,卸载脚本后它们不会被删除。

您需要检查脚本是否已经加载,并且不要加载超过一次:

mounted() {
  const gsc = document.getElementById('grecaptchascript');
  if (!gsc) {
    const
      googleRecaptchaScript = document.createElement('script'),
      recaptchaURL = 'https://www.google.com/recaptcha/api.js';
    googleRecaptchaScript.setAttribute('src', recaptchaURL);
    googleRecaptchaScript.setAttribute('id', 'grecaptchascript');
    document.head.appendChild(googleRecaptchaScript);
  }
}