清除 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
是有问题的,因为我们正在谈论重复的元素。我稍后会更改它。如果有帮助,请考虑按任意属性进行选择的一般情况。我尝试了其他属性但没有成功。
我不确定问题到底是什么,但为了将来参考,此解决方案有效并且对我的情况来说似乎相当不错,因为它选择 script
的 src
的前缀属性:
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);
}
}
我正在以编程方式将必要的脚本添加到我的一些 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
是有问题的,因为我们正在谈论重复的元素。我稍后会更改它。如果有帮助,请考虑按任意属性进行选择的一般情况。我尝试了其他属性但没有成功。
我不确定问题到底是什么,但为了将来参考,此解决方案有效并且对我的情况来说似乎相当不错,因为它选择 script
的 src
的前缀属性:
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);
}
}