Comment ajouter des scripts JS externes aux composants VueJS

151

Je dois utiliser deux scripts externes pour les passerelles de paiement. À l'heure actuelle, les deux sont placés dans le index.htmlfichier. Cependant, je ne veux pas charger ces fichiers au début même. La passerelle de paiement est nécessaire uniquement lorsque l'utilisateur ouvre un composant spécifique ( using router-view).

Y'a-t-il une quelconque façon de réussir cela?

Gijo Varghese
la source
Pouvez-vous utiliser /public/index.htmlpour le faire?
user3290525

Réponses:

240

Un moyen simple et efficace de résoudre cela, c'est en ajoutant votre script externe dans la vue mounted()de votre composant. Je vais vous illustrer avec le script 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>

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

mejiamanuel57
la source
22
created()méthode ne peut pas obtenir le document, utilisez à la mounted()place
Barlas Apaydin
15
Ajoutez recaptchaScript.async = trueavant de l'ajouter à la tête.
Joe Eifert
6
recaptchaScript.defer = truepeut également convenir à quelqu'un
Tarasovych
3
c'est certainement la meilleure réponse car vue est destinée à être un framework de composant à fichier unique. à moins que votre fichier actuel ne soit extrêmement volumineux, je suggérerais d'ajouter la fonction à vos sections montées () et / ou beforeMount () de vos balises de script ... veuillez consulter la fonctionnalité beforeMount () avant de décider de vuejs.org/v2/api/#beforeMount
Kyle Joeckel le
1
@KeisukeNagakawa théoriquement, oui. Voir cette réponse stackoverflow.com/questions/1605899/…
Jeff Ryan le
28

J'ai téléchargé un modèle HTML fourni avec des fichiers js et jquery personnalisés. J'ai dû attacher ces js à mon application. et continuez avec Vue.

J'ai trouvé ce plugin, c'est un moyen propre d'ajouter des scripts externes à la fois via CDN et à partir de fichiers statiques 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
la source
C'est une façon vraiment simple et soignée de le faire. J'aime cette méthode
Vixson
25

en utilisant webpack et vue loader, vous pouvez faire quelque chose comme ça

il attend que le script externe se charge avant de créer le composant, donc globar vars etc sont disponibles dans le composant

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 droïde
la source
Je l'ai utilisé en monté
Oranit Dar le
>> "Où placez-vous ce code?" : Il est dans la section composants de votre composant vuejs.
ADM-IT
7

Utilisez-vous l'un des modèles de démarrage Webpack pour vue ( https://github.com/vuejs-templates/webpack )? Il est déjà configuré avec vue-loader ( https://github.com/vuejs/vue-loader ). Si vous n'utilisez pas de modèle de démarrage, vous devez configurer webpack et vue-loader.

Vous pouvez ensuite importvos scripts vers les composants pertinents (fichier unique). Avant cela, vous devez exportde vos scripts ce que vous voulez importà vos composants.

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

~ Modifier ~
Vous pouvez importer à partir de ces wrappers:
- https://github.com/matfish2/vue-stripe
- https://github.com/khoanguyen96/vue-paypal-checkout

ba_ul
la source
2
Ces scripts proviennent de paypal et stripe. Je ne peux pas télécharger le mettre le fichier localement
Gijo Varghese
2
Ces emballages résolvent-ils votre problème? github.com/matfish2/vue-stripe et github.com/khoanguyen96/vue-paypal-checkout
ba_ul
réponse boiteuse ... expliquez pourquoi vue loader est nécessaire
Kyle Joeckel
6

Vous pouvez utiliser le package vue-head pour ajouter des scripts et d'autres balises à la tête de votre composant vue.

C'est aussi simple que:

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

Consultez ce lien pour plus d'exemples.

pamekar
la source
quel est l'avantage ou la différence par rapport à l'utilisation de vuex store?
Kyle Joeckel le
6

Si vous essayez d'incorporer des scripts js externes au modèle de composant vue.js, procédez comme suit:

Je voulais ajouter un code d'intégration javascript externe à mon composant comme ceci:

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

Et Vue m'a montré cette erreur:

Les modèles ne doivent être responsables que du mappage de l'état à l'interface utilisateur. Évitez de placer des balises avec des effets secondaires dans vos modèles, par exemple, car elles ne seront pas analysées.


La façon dont je l'ai résolu en ajoutanttype="application/javascript" ( voir cette question pour en savoir plus sur le type MIME pour js ):

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


Vous remarquerez peut-être l' deferattribut. Si vous voulez en savoir plus, regardez cette vidéo de Kyle

roli roli
la source
4

Vous pouvez charger le script dont vous avez besoin avec une solution basée sur des promesses:

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

    }
  }
}

Veuillez noter que this.$rootc'est un peu piraté et que vous devriez plutôt utiliser une solution vuex ou eventHub pour les événements globaux.

Vous feriez de ce qui précède un composant et l'utiliseriez là où c'est nécessaire, il ne chargera le script que lorsqu'il est utilisé.

hitautodestruct
la source
3

Cela peut être fait simplement comme ceci.

  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
la source
2

Pour garder les composants propres, vous pouvez utiliser des mixins.

Sur votre composant, importez un fichier mixin externe.

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 (j'inclus ceci, s'il y en a qui restent bloqués à l'importation)

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

La réponse principale de créer une balise dans le montage est bonne, mais cela pose quelques problèmes: si vous modifiez votre lien plusieurs fois, il répétera la création de la balise encore et encore.

J'ai donc créé un script pour résoudre ce problème, et vous pouvez supprimer la balise si vous le souhaitez.

C'est très simple, mais cela peut vous faire gagner du temps pour le créer vous-même.

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

Et vous pouvez l'utiliser comme ceci:

// 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
la source
2
Une fois qu'un script est chargé, il est déjà en mémoire. Le retirer du dom ne supprime pas son empreinte.
danbars
1

Vous pouvez utiliser vue-loader et coder vos composants dans leurs propres fichiers (composants à fichier unique). Cela vous permettra d'inclure des scripts et des css par composant.

Daniel D
la source
4
Ces scripts proviennent de paypal et stripe. Je ne peux pas télécharger le mettre le fichier localement
Gijo Varghese
1
le lien est rompu
Roberto
Vous pouvez télécharger les scripts externes, afficher la source, copier / coller dans votre propre fichier.
minimallinux
1
@minimallinux Dans le cas de Stripe et Paypal, cela enfreindra PCI-DSS. Alors ne fais pas ça.
Duncan Jones
0

La solution la plus simple est d'ajouter le script dans le index.htmlfichier de votre vue-project

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
la source