我必须为支付网关使用两个外部脚本。

现在两者都放在index.html文件中。

但是,我不想在开头本身就加载这些文件。

只有在用户打开特定组件(使用路由器视图)时才需要支付网关。

有办法实现这个目标吗?

谢谢。


当前回答

解决这个问题的一个简单而有效的方法是将外部脚本添加到组件的vue mounted()中。我将用谷歌Recaptcha脚本为您演示:

<template>
   .... your HTML
</template>

<script>
  export default {
    data: () => ({
      ......data of your component
    }),
    mounted() {
      let recaptchaScript = document.createElement('script')
      recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
      document.head.appendChild(recaptchaScript)
    },
    methods: {
      ......methods of your component
    }
  }
</script>

来源:https://medium.com/@lassiuosukainen how-to-include-a-script-tag-on-a-vue-component-fe10940af9e8

其他回答

来自mejiamanuel57的答案很好,但我想添加几个适合我的技巧(我花了几个小时在上面)。首先,我需要使用“窗口”范围。此外,如果您需要访问“onload”函数内的任何Vue元素,则需要为“this”实例创建一个新变量。

<script>
import { mapActions } from "vuex";
export default {
  name: "Payment",
  methods: {
    ...mapActions(["aVueAction"])
  },
  created() {
    let paywayScript = document.createElement("script");
    let self = this;
    paywayScript.onload = () => {
      // call to Vuex action.
      self.aVueAction();
      // call to script function
      window.payway.aScriptFunction();
    };
    // paywayScript.async = true;
    paywayScript.setAttribute(
      "src",
      "https://api.payway.com.au/rest/v1/payway.js"
    );
    document.body.appendChild(paywayScript);
  }
};
</script>

我在Vue 2.6上使用它。这里有一个关于“let self = this;”在Javascript中如何工作的技巧的解释:

var that = this;在JavaScript中是什么意思?

好吧,这是我在qiokian(一个live2d动画人物vuejs组件)中的实践:

(以下来自src/qiokian.vue文件)

<script>
export default {
    data() {
        return {
            live2d_path:
                'https://cdn.jsdelivr.net/gh/knowscount/live2d-widget@latest/',
            cdnPath: 'https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/',
        }
    },
<!-- ... -->
        loadAssets() {
            // load waifu.css live2d.min.js waifu-tips.js
            if (screen.width >= 768) {
                Promise.all([
                    this.loadExternalResource(
                        this.live2d_path + 'waifu.css',
                        'css'
                    ),
<!-- ... -->
        loadExternalResource(url, type) {
            // note: live2d_path parameter should be an absolute path
            // const live2d_path =
            //   "https://cdn.jsdelivr.net/gh/knowscount/live2d-widget@latest/";
            //const live2d_path = "/live2d-widget/";
            return new Promise((resolve, reject) => {
                let tag

                if (type === 'css') {
                    tag = document.createElement('link')
                    tag.rel = 'stylesheet'
                    tag.href = url
                } else if (type === 'js') {
                    tag = document.createElement('script')
                    tag.src = url
                }
                if (tag) {
                    tag.onload = () => resolve(url)
                    tag.onerror = () => reject(url)
                    document.head.appendChild(tag)
                }
            })
        },
    },
}

顶部的创建标签的答案是好的,但它有一些问题:如果你改变你的链接多次,它会重复创建标签一遍又一遍。

所以我创建了一个脚本来解决这个问题,如果你愿意,你可以删除标签。

它非常简单,但可以节省你自己创建的时间。

// PROJECT/src/assets/external.js

function head_script(src) {
    if(document.querySelector("script[src='" + src + "']")){ return; }
    let script = document.createElement('script');
    script.setAttribute('src', src);
    script.setAttribute('type', 'text/javascript');
    document.head.appendChild(script)
}

function body_script(src) {
    if(document.querySelector("script[src='" + src + "']")){ return; }
    let script = document.createElement('script');
    script.setAttribute('src', src);
    script.setAttribute('type', 'text/javascript');
    document.body.appendChild(script)
}

function del_script(src) {
    let el = document.querySelector("script[src='" + src + "']");
    if(el){ el.remove(); }
}


function head_link(href) {
    if(document.querySelector("link[href='" + href + "']")){ return; }
    let link = document.createElement('link');
    link.setAttribute('href', href);
    link.setAttribute('rel', "stylesheet");
    link.setAttribute('type', "text/css");
    document.head.appendChild(link)
}

function body_link(href) {
    if(document.querySelector("link[href='" + href + "']")){ return; }
    let link = document.createElement('link');
    link.setAttribute('href', href);
    link.setAttribute('rel', "stylesheet");
    link.setAttribute('type', "text/css");
    document.body.appendChild(link)
}

function del_link(href) {
    let el = document.querySelector("link[href='" + href + "']");
    if(el){ el.remove(); }
}

export {
    head_script,
    body_script,
    del_script,
    head_link,
    body_link,
    del_link,
}

你可以这样使用它:

// PROJECT/src/views/xxxxxxxxx.vue

......

<script>
    import * as external from '@/assets/external.js'
    export default {
        name: "xxxxxxxxx",
        mounted(){
            external.head_script('/assets/script1.js');
            external.body_script('/assets/script2.js');
            external.head_link('/assets/style1.css');
            external.body_link('/assets/style2.css');
        },
        destroyed(){
            external.del_script('/assets/script1.js');
            external.del_script('/assets/script2.js');
            external.del_link('/assets/style1.css');
            external.del_link('/assets/style2.css');
        },
    }
</script>

......

你可以加载你需要的基于承诺的解决方案的脚本:

export default {
  data () {
    return { is_script_loading: false }
  },
  created () {
    // If another component is already loading the script
    this.$root.$on('loading_script', e => { this.is_script_loading = true })
  },
  methods: {
    load_script () {
      let self = this
      return new Promise((resolve, reject) => {

        // if script is already loading via another component
        if ( self.is_script_loading ){
          // Resolve when the other component has loaded the script
          this.$root.$on('script_loaded', resolve)
          return
        }

        let script = document.createElement('script')
        script.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
        script.async = true
        
        this.$root.$emit('loading_script')

        script.onload = () => {
          /* emit to global event bus to inform other components
           * we are already loading the script */
          this.$root.$emit('script_loaded')
          resolve()
        }

        document.head.appendChild(script)

      })

    },
  
    async use_script () {
      try {
        await this.load_script()
        // .. do what you want after script has loaded
      } catch (err) { console.log(err) }

    }
  }
}

请注意这一点。$root有点粗糙,对于全局事件,您应该使用vuex或甚至enthub解决方案。

你可以把上面的内容变成一个组件,并在任何需要的地方使用它,它只会在使用时加载脚本。

注意:这是一台Vue 2。基于X的解。Vue 3已停止支持$on。

使用webpack和vue加载器,你可以这样做

在创建组件之前,它会等待外部脚本加载,因此在组件中可以使用globar vars等

components: {
 SomeComponent: () => {
  return new Promise((resolve, reject) => {
   let script = document.createElement('script')
   script.onload = () => {
    resolve(import(someComponent))
   }
   script.async = true
   script.src = 'https://maps.googleapis.com/maps/api/js?key=APIKEY&libraries=places'
   document.head.appendChild(script)
  })
 }
},