Como adicionar scripts JS externos aos componentes do VueJS

150

Eu tenho que usar dois scripts externos para os gateways de pagamento. No momento, ambos são colocados no index.htmlarquivo. No entanto, não quero carregar esses arquivos no início. O gateway de pagamento é necessário apenas quando o usuário abre um componente específico ( using router-view).

Existe alguma maneira de conseguir isso?

Gijo Varghese
fonte
Você pode usar /public/index.htmlpara fazer isso?
user3290525

Respostas:

239

Uma maneira simples e eficaz de resolver isso é adicionar seu script externo ao valor mounted()do seu componente. Ilustrarei você com o script do Google 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>

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

mejiamanuel57
fonte
22
created()método não pode obter documento, o uso mounted()em vez
Barlas Apaydin
15
Adicione recaptchaScript.async = trueantes de anexá-lo à cabeça.
21718 Joe Eifert
6
recaptchaScript.defer = truepode ser também adequado para alguém
Tarasovych
3
essa é certamente a melhor resposta, pois o vue pretende ser uma estrutura de componente de arquivo único. a menos que seu arquivo atual seja extremamente grande, sugiro adicionar a função às suas seções mounted () e / ou beforeMount () de suas tags de script ... consulte a funcionalidade beforeMount () antes de decidir vuejs.org/v2/api/#beforeMount
Kyle Joeckel 29/04/19
1
@KeisukeNagakawa teoricamente, sim. Veja esta resposta stackoverflow.com/questions/1605899/…
Jeff Ryan
28

Fiz o download de um modelo HTML que vem com arquivos js personalizados e jquery. Eu tive que anexar esses js ao meu aplicativo. e continue com o Vue.

Encontrado este plug-in, é uma maneira limpa de adicionar scripts externos via CDN e de arquivos estáticos https://www.npmjs.com/package/vue-plugin-load-script

// local files
// you have to put your scripts into the public folder. 
// that way webpack simply copy these files as it is.
Vue.loadScript("/js/jquery-2.2.4.min.js")

// cdn
Vue.loadScript("https://maps.googleapis.com/maps/api/js")
PJ3
fonte
Essa é uma maneira realmente elegante e simples de fazer isso. Eu gosto desse método
Vixson 30/03
25

usando o webpack e o vue loader, você pode fazer algo assim

aguarda o carregamento do script externo antes de criar o componente, para que vars globares etc. estejam disponíveis no componente

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)
  })
 }
},
mons droid
fonte
Eu usei-o em montado
Oranit Dar 24/02
>> "Onde você coloca esse código?" : Está na seção de componentes no seu componente vuejs.
ADM-IT
7

Você está usando um dos modelos iniciais do Webpack para vue ( https://github.com/vuejs-templates/webpack )? Ele já vem configurado com o vue-loader ( https://github.com/vuejs/vue-loader ). Se você não estiver usando um modelo inicial, precisará configurar o webpack e o vue-loader.

Você pode então importseus scripts para os componentes relevantes (arquivo único). Antes disso, você precisa exportdos seus scripts o que deseja importpara seus componentes.

Importação do ES6:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- http://exploringjs.com/es6/ch_modules.html

~ Editar ~
Você pode importar desses invólucros:
- https://github.com/matfish2/vue-stripe
- https://github.com/khoanguyen96/vue-paypal-checkout

ba_ul
fonte
2
Esses scripts são de paypal e stripe. Eu não posso baixar a colocar o arquivo localmente
Gijo Varghese
2
Esses invólucros resolvem seu problema? github.com/matfish2/vue-stripe e github.com/khoanguyen96/vue-paypal-checkout
ba_ul
resposta coxo ... dar explicação sobre o porquê loader vue é necessária
Kyle Joeckel
6

Você pode usar o pacote vue-head para adicionar scripts e outras tags ao cabeçalho do seu componente vue.

É tão simples quanto:

var myComponent = Vue.extend({
  data: function () {
    return {
      ...
    }
  },
  head: {
    title: {
      inner: 'It will be a pleasure'
    },
    // Meta tags
    meta: [
      { name: 'application-name', content: 'Name of my application' },
      { name: 'description', content: 'A description of the page', id: 'desc' }, // id to replace intead of create element
      // ...
      // Twitter
      { name: 'twitter:title', content: 'Content Title' },
      // with shorthand
      { n: 'twitter:description', c: 'Content description less than 200 characters'},
      // ...
      // Google+ / Schema.org
      { itemprop: 'name', content: 'Content Title' },
      { itemprop: 'description', content: 'Content Title' },
      // ...
      // Facebook / Open Graph
      { property: 'fb:app_id', content: '123456789' },
      { property: 'og:title', content: 'Content Title' },
      // with shorthand
      { p: 'og:image', c: 'https://example.com/image.jpg' },
      // ...
    ],
    // link tags
    link: [
      { rel: 'canonical', href: 'http://example.com/#!/contact/', id: 'canonical' },
      { rel: 'author', href: 'author', undo: false }, // undo property - not to remove the element
      { rel: 'icon', href: require('./path/to/icon-16.png'), sizes: '16x16', type: 'image/png' }, 
      // with shorthand
      { r: 'icon', h: 'path/to/icon-32.png', sz: '32x32', t: 'image/png' },
      // ...
    ],
    script: [
      { type: 'text/javascript', src: 'cdn/to/script.js', async: true, body: true}, // Insert in body
      // with shorthand
      { t: 'application/ld+json', i: '{ "@context": "http://schema.org" }' },
      // ...
    ],
    style: [
      { type: 'text/css', inner: 'body { background-color: #000; color: #fff}', undo: false },
      // ...
    ]
  }
})

Confira este link para mais exemplos.

pamekar
fonte
qual a vantagem ou diferença disso sobre o uso da loja vuex?
Kyle Joeckel 29/04/19
6

Se você estiver tentando incorporar scripts js externos ao modelo de componente vue.js., siga abaixo:

Eu queria adicionar um código de incorporação de javascript externo ao meu componente assim:

<template>
  <div>
    This is my component
    <script src="https://badge.dimensions.ai/badge.js"></script>
  </div>
<template>

E Vue me mostrou este erro:

Os modelos devem ser responsáveis ​​apenas pelo mapeamento do estado para a interface do usuário. Evite colocar tags com efeitos colaterais em seus modelos, como, pois eles não serão analisados.


A maneira como resolvi foi adicionandotype="application/javascript" ( Veja esta pergunta para saber mais sobre o tipo MIME para js ):

<script type="application/javascript" defer src="..."></script>


Você pode perceber o deferatributo. Se você quiser saber mais, assista a este vídeo de Kyle

roli roli
fonte
4

Você pode carregar o script necessário com uma solução baseada em promessa:

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) }

    }
  }
}

Por favor note que this.$rooté um pouco hacky e você deve usar um vuex ou eventHub solução para os eventos globais em vez.

Você transformaria o item acima em um componente e o utilizava sempre que necessário; ele carregará o script apenas quando usado.

hitautodestruct
fonte
3

Isso pode ser feito simplesmente assim.

  created() {
    var scripts = [
      "https://cloudfront.net/js/jquery-3.4.1.min.js",
      "js/local.js"
    ];
    scripts.forEach(script => {
      let tag = document.createElement("script");
      tag.setAttribute("src", script);
      document.head.appendChild(tag);
    });
  }
Awais Jameel
fonte
2

Para manter os componentes limpos, você pode usar mixins.

No seu componente, importe o arquivo mixin externo.

Profile.vue

import externalJs from '@client/mixins/externalJs';

export default{
  mounted(){
    this.externalJsFiles();
  }
}

externalJs.js

import('@JSassets/js/file-upload.js').then(mod => {
  // your JS elements 
})

babelrc (eu incluo isso, se algum ficar preso na importação)

{
  "presets":["@babel/preset-env"],
  "plugins":[
    [
     "module-resolver", {
       "root": ["./"],
       alias : {
         "@client": "./client",
         "@JSassets": "./server/public",
       }
     }
    ]
}
Tushar Roy
fonte
2

A resposta principal de criar tag no montado é boa, mas há alguns problemas: Se você alterar seu link várias vezes, ele repetirá a criação de tags repetidamente.

Então, eu criei um script para resolver isso, e você pode excluir a tag, se desejar.

É muito simples, mas pode economizar seu tempo para criá-lo sozinho.

// 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,
}

E você pode usá-lo assim:

// 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>

......
oraant
fonte
2
Depois que um script é carregado, ele já está na memória. Removê-lo do dom não remove sua pegada.
danbars 23/02
1

Você pode usar o vue-loader e codificar seus componentes em seus próprios arquivos (componentes de arquivo único). Isso permitirá que você inclua scripts e css em uma base de componente.

Daniel D
fonte
4
Esses scripts são de paypal e stripe. Eu não posso baixar a colocar o arquivo localmente
Gijo Varghese
1
o link está quebrado
Roberto
Você pode baixar os scripts externos, visualizar a fonte, copiar / colar no seu próprio arquivo.
Minimallinux
1
@minimallinux No caso do Stripe e Paypal, isso violará o PCI-DSS. Então não faça isso.
Duncan Jones
0

A solução mais simples é adicionar o script no index.htmlarquivo do seu projeto vue

index.html:

 <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>vue-webpack</title>
      </head>
      <body>
        <div id="app"></div>
        <!-- start Mixpanel --><script type="text/javascript">(function(c,a){if(!a.__SV){var b=window;try{var d,m,j,k=b.location,f=k.hash;d=function(a,b){return(m=a.match(RegExp(b+"=([^&]*)")))?m[1]:null};f&&d(f,"state")&&(j=JSON.parse(decodeURIComponent(d(f,"state"))),"mpeditor"===j.action&&(b.sessionStorage.setItem("_mpcehash",f),history.replaceState(j.desiredHash||"",c.title,k.pathname+k.search)))}catch(n){}var l,h;window.mixpanel=a;a._i=[];a.init=function(b,d,g){function c(b,i){var a=i.split(".");2==a.length&&(b=b[a[0]],i=a[1]);b[i]=function(){b.push([i].concat(Array.prototype.slice.call(arguments,
    0)))}}var e=a;"undefined"!==typeof g?e=a[g]=[]:g="mixpanel";e.people=e.people||[];e.toString=function(b){var a="mixpanel";"mixpanel"!==g&&(a+="."+g);b||(a+=" (stub)");return a};e.people.toString=function(){return e.toString(1)+".people (stub)"};l="disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split(" ");
    for(h=0;h<l.length;h++)c(e,l[h]);var f="set set_once union unset remove delete".split(" ");e.get_group=function(){function a(c){b[c]=function(){call2_args=arguments;call2=[c].concat(Array.prototype.slice.call(call2_args,0));e.push([d,call2])}}for(var b={},d=["get_group"].concat(Array.prototype.slice.call(arguments,0)),c=0;c<f.length;c++)a(f[c]);return b};a._i.push([b,d,g])};a.__SV=1.2;b=c.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?
    MIXPANEL_CUSTOM_LIB_URL:"file:"===c.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";d=c.getElementsByTagName("script")[0];d.parentNode.insertBefore(b,d)}})(document,window.mixpanel||[]);
    mixpanel.init("xyz");</script><!-- end Mixpanel -->
        <script src="/dist/build.js"></script>
      </body>
    </html>
Tanya Talwar
fonte