带有 Quasar 和 Vue 3 的外部脚本标签(第 3 方 javascript)?

External script tag (3rd party javascript) with Quasar and Vue 3?

我需要向我的 Quasar/Vue 3 应用添加一些外部 JavaScript 脚本。

例如,我需要在我的 Zoho Desk 应用程序的某些页面上使用它:

<script type="text/javascript" nonce="{place_your_nonce_value_here}" src="https://desk.zoho.com.au/portal/api/web/inapp/9999999999?orgId=111111111" defer > </script>

另一个例子是 Stripe.js,我只希望它在支付页面上加载:

<script src="https://js.stripe.com/v3/"></script>

我想我还有很多其他需要选择性地注入这些第 3 方 JavaScript 片段的例子。

Quasar 有引导文件,这可能对此有好处,但我不确定如何用它来实现它,或者即使这是最好的解决方案。

欢迎任何指导。

正确答案是它取决于 third-party 库、它提供的安装方式以及它是否具有与 Vue.js and/or Quasar 的集成支持。

例如 Stripe,您可以将其安装为 npm 包并像这样使用它(non-tested 代码):

<script setup> 
import { onMounted } from 'vue'
import {loadStripe} from '@stripe/stripe-js';

onMounted(() => {
const stripe = await loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
})
</script>

Third-party 带有脚本标签安装的库

我假设,问题更多是关于如何添加仅提供 script tag 安装的 third-party 库:

  1. 创建一个 JS 文件 (load-script.js):
function createTag(src) {
  let script
  
  script = document.createElement('script')
  script.type = 'application/javascript'
  script.async = true
  script.src = src
  
  return script
}

function addListeners(script, resolve, reject) {
  script.addEventListener('error', reject)
  script.addEventListener('abort', reject)
  script.addEventListener('load', function loadScriptHandler() {
    script.setAttribute('data-loaded', '')
    resolve(removeScript.bind(null, script))
  })
}

export function removeScript(scriptOrSrc) {
  let script
  
  if (typeof scriptOrSrc === 'string') {
    script = document.querySelector(`script[src="${scriptOrSrc}"]`)
  } else {
    script = scriptOrSrc
  }
  
  if (script) script.parentNode.removeChild(script)
}

export function loadScript(src) {
  return new Promise((resolve, reject) => {
    let script = document.querySelector(`script[src="${src}"]`)
    
    if (script && script.hasAttribute('data-loaded')) {
      resolve(removeScript.bind(null, script))
      return
    }
    
    script = createTag(src)
    addListeners(script, resolve, reject)
    document.head.appendChild(script)
  })
}
  1. 使用该函数加载或删除组件中的脚本标签:
<script setup>
import { onUnmounted } from 'vue'
import { loadScript, removeScript } from '../load-script'

const src = '3rd-part-url'

loadScript(src)

onUnmounted(() => removeScript(src))
</script>

采用.then方法:

<script setup>
import { onUnmounted } from 'vue'
import { loadScript } from '../load-script'

let removeScript

loadScript('3rd-part-url').then((removeScriptCallback) => {
  // script is loaded use `removeScriptCallback()` to remove it
  removeScript = removeScriptCallback
})

onUnmounted(() => removeScript())
</script>

选项 API:

<script>
import { loadScript, removeScript } from './load-script.js'

export default {
  created() {
    this.externalScriptUrl = '...'
    loadScript(externalScriptUrl).then(removeScript => {
      // script is loaded use `removeScript()` to remove it
    })
  },

  unmounted() {
    removeScript(this.externalScriptUrl)
  }
}
</script>

说明

load-script.js 文件使用 async 属性。 它为脚本标签注册错误、中止和加载事件。然后 load 事件解析 then 块,而错误和中止落在承诺的 catch 块中。据我所知,由于事件已在元素中注册,因此无需删除侦听器。

script 标签将附加在 head 中。

可以通过添加对脚本属性的支持或将其附加到 body 中轻松增强脚本,但出于此答案的目的,最好保持简单。


须知

  1. 您可能会或可能不会遇到动态加载外部 js 的安全问题。
  2. 删除脚本标签,并不意味着您卸载了脚本:

any code loaded as part of the external JavaScript file remains in the browser's memory. That is to say, you can still access variables, functions etc that were added when the external file first loaded