วิธีเพิ่มสคริปต์ JS ภายนอกให้กับ VueJS Components


151

ฉันจะใช้สคริปต์ภายนอกสองสคริปต์สำหรับเกตเวย์การชำระเงิน ตอนนี้ทั้งคู่ถูกใส่ในindex.htmlไฟล์ อย่างไรก็ตามฉันไม่ต้องการโหลดไฟล์เหล่านี้ในตอนต้น จำเป็นต้องใช้เกตเวย์การชำระเงินเฉพาะเมื่อผู้ใช้เปิดส่วนประกอบเฉพาะ ( using router-view)

อย่างไรก็ตามมีเพื่อให้บรรลุนี้


คุณสามารถใช้/public/index.htmlเพื่อทำมันได้หรือไม่
user3290525

คำตอบ:


240

วิธีที่ง่ายและมีประสิทธิภาพในการแก้ปัญหานี้คือการเพิ่มสคริปต์ภายนอกของคุณลงใน vue mounted()ขององค์ประกอบของคุณ ฉันจะแสดงให้คุณเห็นด้วยสคริปต์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>

ที่มา: https://medium.com/@lassiuosukainen/how-to-include-a-script-tag-on-a-vue-component-fe10940af9e8


22
created()วิธีการไม่สามารถรับเอกสารใช้mounted()แทน
Barlas Apaydin

15
เพิ่มrecaptchaScript.async = trueก่อนที่จะผนวกเข้ากับส่วนหัว
Joe Eifert

6
recaptchaScript.defer = trueอาจเหมาะสำหรับใครบางคน
Tarasovych

3
นี่เป็นคำตอบที่ดีที่สุดเนื่องจาก vue ตั้งใจให้เป็นเฟรมเวิร์กองค์ประกอบไฟล์เดียว นอกเสียจากไฟล์ compnent ปัจจุบันของคุณมีขนาดใหญ่มากฉันขอแนะนำให้เพิ่มฟังก์ชั่นในส่วนที่เมานต์ () และ / หรือ beforeMount () ของแท็กสคริปต์ของคุณ ... โปรดดูฟังก์ชันการทำงาน beforeMount () ก่อนตัดสินใจvuejs.org/v2/api/#beforeMount
Kyle Joeckel

1
@ KeisukeNagakawa ตามหลักวิชาใช่แล้ว ดูคำตอบนี้stackoverflow.com/questions/1605899/…
Jeff Ryan

28

ฉันดาวน์โหลดเทมเพลต HTML ที่มาพร้อมกับไฟล์ js และ jquery ที่กำหนดเอง ฉันต้องแนบ js เหล่านี้กับแอปของฉัน และดำเนินการต่อด้วย Vue

พบปลั๊กอินนี้เป็นวิธีที่สะอาดในการเพิ่มสคริปต์ภายนอกทั้งทาง CDN และจากไฟล์คงที่ 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")

นี่เป็นวิธีที่เรียบง่ายและเรียบร้อยมาก ฉันชอบวิธีนี้
Vixson

25

การใช้ webpack และ vue loader คุณสามารถทำสิ่งนี้ได้

มันรอให้สคริปต์ภายนอกโหลดก่อนที่จะสร้างองค์ประกอบดังนั้น globar vars etc จึงมีอยู่ในส่วนประกอบ

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

ฉันใช้มันในการติดตั้ง
Oranit Dar

>> "คุณวางรหัสนี้ที่ไหน" : อยู่ในส่วนคอมโพเนนต์ในคอมโพเนนต์ vuejs ของคุณ
ADM-IT

7

คุณใช้เทมเพลตเริ่มต้นของ Webpack สำหรับ vue ( https://github.com/vuejs-templates/webpack ) หรือไม่ ติดตั้งแล้วพร้อมกับ vue-loader ( https://github.com/vuejs/vue-loader ) หากคุณไม่ได้ใช้เทมเพลตเริ่มต้นคุณต้องตั้งค่า webpack และ vue-loader

จากนั้นคุณสามารถimportสคริปต์ของคุณไปยังองค์ประกอบที่เกี่ยวข้อง (ไฟล์เดียว) ก่อนที่คุณจะต้องexportจากสคริปต์ของคุณสิ่งที่คุณต้องการimportในส่วนของคุณ

การนำเข้า ES6:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- http://exploringjs.com/es6/ch_modules.html

~ แก้ไข ~
คุณสามารถนำเข้าจากอุปกรณ์เสริมเหล่านี้:
- https://github.com/matfish2/vue-stripe
- https://github.com/khoanguyen96/vue-paypal-checkout


2
สคริปต์เหล่านี้มาจาก paypal และแถบ ฉันไม่สามารถดาวน์โหลดใส่ไฟล์ในเครื่องได้
Gijo Varghese

2
wrappers เหล่านี้แก้ปัญหาของคุณหรือไม่ github.com/matfish2/vue-stripe และgithub.com/khoanguyen96/vue-paypal-checkout
ba_ul

ตอบอ่อนแอ ... ให้คำอธิบายว่าทำไมต้องใช้ vue loader
Kyle Joeckel

6

คุณสามารถใช้แพ็กเกจvue-headเพื่อเพิ่มสคริปต์และแท็กอื่น ๆ เข้ากับส่วนหัวของคอมโพเนนต์ vue ของคุณ

มันง่ายเหมือน:

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

ลองดูลิงค์นี้สำหรับตัวอย่างเพิ่มเติม


อะไรคือข้อดีหรือข้อแตกต่างของการใช้ vuex store
Kyle Joeckel

6

หากคุณพยายามฝังสคริปต์ js ภายนอกไปยังเทมเพลตคอมโพเนนต์ vue.js ให้ทำตามด้านล่าง:

ฉันต้องการเพิ่มโค้ดฝังจาวาสคริปต์ภายนอกลงในคอมโพเนนต์ของฉันเช่นนี้:

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

และ Vue พบข้อผิดพลาดนี้ให้ฉัน:

เทมเพลตควรรับผิดชอบการแมปสถานะกับ UI เท่านั้น หลีกเลี่ยงการวางแท็กที่มีผลข้างเคียงในเทมเพลตของคุณเช่นจะไม่มีการแยกวิเคราะห์


วิธีที่ฉันแก้ไขมันคือการเพิ่มtype="application/javascript" ( ดูคำถามนี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับประเภท MIME สำหรับ js ):

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


คุณอาจสังเกตเห็นdeferคุณลักษณะ ถ้าคุณต้องการเรียนรู้เพิ่มเติมดูวิดีโอนี้โดย Kyle


4

คุณสามารถโหลดสคริปต์ที่คุณต้องการด้วยโซลูชันที่อิงตามสัญญา:

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

    }
  }
}

โปรดทราบว่าthis.$rootเป็นการแฮ็กเล็กน้อยและคุณควรใช้โซลูชัน vuexหรือeventHubสำหรับกิจกรรมระดับโลกแทน

คุณจะทำให้องค์ประกอบข้างต้นเป็นองค์ประกอบและใช้งานได้ทุกที่ที่ต้องการมันจะโหลดสคริปต์เมื่อใช้งานเท่านั้น


3

สามารถทำได้อย่างนี้

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

2

เพื่อรักษาองค์ประกอบที่สะอาดคุณสามารถใช้ mixins

ในองค์ประกอบของคุณนำเข้าไฟล์มิกซ์อินภายนอก

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 (ฉันรวมสิ่งนี้ไว้หากมีสิ่งใดติดอยู่กับการนำเข้า)

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

2

คำตอบยอดนิยมของการสร้างแท็กในเมาท์นั้นดี แต่มันมีปัญหา: ถ้าคุณเปลี่ยนลิงค์หลายครั้งมันจะสร้างแท็กซ้ำไปซ้ำมา

ดังนั้นฉันจึงสร้างสคริปต์เพื่อแก้ไขปัญหานี้และคุณสามารถลบแท็กได้หากต้องการ

มันง่ายมาก แต่สามารถประหยัดเวลาในการสร้างด้วยตัวเอง

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

......

2
เมื่อโหลดสคริปต์แล้วจะมีอยู่ในหน่วยความจำแล้ว การลบออกจาก dom ไม่ได้เป็นการลบทิ้ง
danbars

1

คุณสามารถใช้vue-loaderและโค้ดคอมโพเนนต์ของคุณในไฟล์ของตัวเอง (คอมโพเนนต์ไฟล์เดี่ยว) สิ่งนี้จะช่วยให้คุณรวมสคริปต์และ css บนพื้นฐานขององค์ประกอบ


4
สคริปต์เหล่านี้มาจาก paypal และแถบ ฉันไม่สามารถดาวน์โหลดใส่ไฟล์ในเครื่องได้
Gijo Varghese

1
ลิงก์เสีย
Roberto

คุณสามารถดาวน์โหลดสคริปต์ภายนอกดูแหล่งคัดลอก / วางในไฟล์ของคุณเอง
minimallinux

1
@minimallinux ในกรณีของ Stripe และ Paypal นั่นจะเป็นการละเมิด PCI-DSS ดังนั้นอย่าทำอย่างนั้น
Duncan Jones

0

ทางออกที่ง่ายที่สุดคือการเพิ่มสคริปต์ในindex.htmlไฟล์ 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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.