Cómo agregar scripts JS externos a componentes VueJS

151

Tengo que usar dos scripts externos para las pasarelas de pago. En este momento, ambos están en el index.htmlarchivo. Sin embargo, no quiero cargar estos archivos al principio. La pasarela de pago solo se necesita cuando el usuario abre un componente específico ( using router-view).

¿Hay alguna forma de lograr esto?

Gijo Varghese
fuente
¿Puedes usar /public/index.htmlpara hacerlo?
user3290525

Respuestas:

239

Una manera simple y efectiva de resolver esto es mediante la adición de su secuencia de comandos externa a la versión mounted()de su componente. Te ilustraré con el script de 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>

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

mejiamanuel57
fuente
22
created()método no puede obtener el documento, utilice mounted()en su lugar
Barlas Apaydin
15
Agregue recaptchaScript.async = trueantes de agregarlo a la cabeza.
Joe Eifert
66
recaptchaScript.defer = truepuede ser también adecuado para alguien
Tarasovych
3
esta es sin duda la mejor respuesta, ya que vue pretende ser un marco de componentes de un solo archivo. a menos que su archivo actual sea extremadamente grande, sugeriría agregar la función a sus secciones montadas () y / o beforeMount () de sus etiquetas de script ... consulte la funcionalidad beforeMount () antes de decidir vuejs.org/v2/api/#beforeMount
Kyle Joeckel
1
@KeisukeNagakawa teóricamente, sí. Ver esta respuesta stackoverflow.com/questions/1605899/…
Jeff Ryan
28

He descargado una plantilla HTML que viene con archivos js personalizados y jquery. Tuve que adjuntar esos js a mi aplicación. y continuar con Vue.

Encontré este complemento, es una forma limpia de agregar scripts externos tanto a través de CDN como de archivos 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
fuente
Esta es una forma realmente ordenada y simple de hacerlo. Me gusta este método
Vixson
25

usando webpack y vue loader puedes hacer algo como esto

espera a que se cargue el script externo antes de crear el componente, por lo que los vars de globar, etc. están disponibles en el 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
fuente
Lo usé en montado
Oranit Dar
>> "¿Dónde colocas este código?" : Está en la sección de componentes en su componente vuejs.
ADM-IT
7

¿Está utilizando una de las plantillas de inicio de Webpack para vue ( https://github.com/vuejs-templates/webpack )? Ya viene configurado con vue-loader ( https://github.com/vuejs/vue-loader ). Si no está utilizando una plantilla de inicio, debe configurar webpack y vue-loader.

A continuación, puede guiar importsus scripts a los componentes relevantes (archivo único). Antes de eso, debe exportde sus scripts lo que quiere importa sus componentes.

Importación de ES6:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- http://exploringjs.com/es6/ch_modules.html

~ Editar ~
Puede importar desde estos contenedores:
- https://github.com/matfish2/vue-stripe
- https://github.com/khoanguyen96/vue-paypal-checkout

ba_ul
fuente
2
Estos scripts son de paypal y stripe. No puedo descargar poner el archivo localmente
Gijo Varghese
2
¿Estas envolturas resuelven su problema? github.com/matfish2/vue-stripe y github.com/khoanguyen96/vue-paypal-checkout
ba_ul
mala respuesta ... dar una explicación de por qué se requiere vue loader
Kyle Joeckel
6

Puede usar el paquete vue-head para agregar scripts y otras etiquetas al encabezado de su componente vue.

Es tan simple como:

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 },
      // ...
    ]
  }
})

Mira este enlace para más ejemplos.

pamekar
fuente
¿Cuál es la ventaja o la diferencia de esto sobre el uso de vuex store?
Kyle Joeckel
6

Si está intentando incrustar secuencias de comandos js externas en la plantilla del componente vue.js, siga a continuación:

Quería agregar un código de inserción de JavaScript externo a mi componente como este:

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

Y Vue me mostró este error:

Las plantillas solo deben ser responsables de asignar el estado a la interfaz de usuario. Evite colocar etiquetas con efectos secundarios en sus plantillas, por ejemplo, ya que no se analizarán.


La forma en que lo resolví fue agregando type="application/javascript" ( Consulte esta pregunta para obtener más información sobre el tipo MIME para js ):

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


Puedes notar el deferatributo. Si quieres aprender más mira este video de Kyle

roli roli
fuente
4

Puede cargar el script que necesita con una solución basada en promesas:

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

    }
  }
}

Tenga en cuenta que this.$rootes un poco hacky y debe usar un vuex o eventHub solución para los eventos globales en su lugar.

Haría lo anterior en un componente y lo usaría donde sea necesario, solo cargará el script cuando se use.

Hitautodestruct
fuente
3

Esto puede hacerse simplemente así.

  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
fuente
2

Para mantener los componentes limpios, puede usar mixins.

En su componente, importe el archivo mixto 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 (incluyo esto, si alguno se atasca en la importación)

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

La respuesta principal de crear etiqueta en montado es buena, pero tiene algunos problemas: si cambia su enlace varias veces, repetirá crear etiqueta una y otra vez.

Así que creé un script para resolver esto, y puede eliminar la etiqueta si lo desea.

Es muy simple, pero puede ahorrarle tiempo para crearlo usted mismo.

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

Y puedes usarlo así:

// 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
fuente
2
Una vez que se carga un script, ya está en la memoria. Eliminarlo del dom no elimina su huella.
Danbars
1

Puede usar vue-loader y codificar sus componentes en sus propios archivos (componentes de un solo archivo). Esto le permitirá incluir scripts y css por componentes.

Daniel D
fuente
44
Estos scripts son de paypal y stripe. No puedo descargar poner el archivo localmente
Gijo Varghese
1
el enlace está roto
Roberto
Puede descargar los scripts externos, ver el código fuente, copiar / pegar en su propio archivo.
minimallinux
1
@minimallinux En el caso de Stripe y Paypal, eso violará PCI-DSS. Entonces no hagas eso.
Duncan Jones
0

La solución más simple es agregar el script en el index.htmlarchivo de su proyecto 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
fuente