Очистка прикрепленного () скрипта в обратном вызове destroy() в компоненте Vue

Я программно добавляю необходимые сценарии в некоторые из моих компонентов 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 здесь проблематично, так как мы говорим о дублирующихся элементах. Я изменю это позже. Пожалуйста, рассмотрите общий случай выбора по любому произвольному атрибуту, если это поможет. Я пробовал другие атрибуты, но безуспешно.


person machine yearning    schedule 20.02.2018    source источник


Ответы (2)


Думаю, что такая очистка не нужна: после загрузки скрипта все определения функций и переменных попадают в глобальную область видимости, а после выгрузки скрипта не удаляются.

Что вам нужно, так это проверить, что скрипты уже загружены и не загружаются более одного раза:

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);
  }
}
person stdob--    schedule 21.02.2018
comment
Я понимаю, почему ваше решение лучше в этом случае. Меня беспокоит, что мы не можем легко очистить определения, вызванные сценарием, конечно, это загромождает пространство имен и объем памяти страницы. - person machine yearning; 21.02.2018
comment
@machineyearning Другой вариант — загрузить скрипты в iframe, которые вы действительно можете удалить. - person stdob--; 21.02.2018

Я не уверен, в чем именно была проблема, но для дальнейшего использования это решение сработало и показалось довольно хорошим для моего случая, потому что оно выбирает префикс атрибута 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 тоже бы сработал, просто я был тупым. И мне все равно было бы интересно, есть ли у кого-нибудь лучшее решение, потому что «ручной» (программный) выбор и удаление элементов со страницы кажется довольно грязным.

person machine yearning    schedule 20.02.2018