【问题标题】:How to include a local JS file into Vue template如何将本地 JS 文件包含到 Vue 模板中
【发布时间】:2019-09-16 23:41:16
【问题描述】:

我想导入一个 JS 文件以在浏览器中与模板一起运行。我尝试了this,但它不起作用,因为我需要在我的脚本运行之前加载所有内容。

让我给你看有问题的vue文件:

<template>
    <div id="canvaspage">

        <canvas id="canvas"></canvas>

        <div id="buttonlist">
            <h5>Select your action:</h5>
            <div class="col">
                <button id="btn1">JS file custom action 1</button>
                <button id="btn2">JS file custom action 2</button>
            </div>
        </div>

    </div>
</template>

<script>
export default {
    name: 'CanvasPage'
}
</script>
...

看到模板上的画布和按钮了吗?我想用纯 JS 和它交互。

以下是 JS 文件尝试执行的示例:

let canvas = document.getElementById('canvas')
let button1 = document.getElementById('btn1')
let button2 = document.getElementById('btn2')

canvas.addEventListener('click', () => {
    console.log('Canvas clicked')
})

button1.addEventListener('click', () => {
    console.log('Button 1 clicked')
})

button2.addEventListener('click', () => {
    console.log('Button 2 clicked')
})

如果我尝试上面链接的解决方案,会发生'canvas'、'button1'和'button2'都是空的,因为 JS 找不到它们。如何让它在 Vue 上运行?

【问题讨论】:

  • 你应该把它打包到一个合适的 ES6 模块中来导出一个函数。然后可以从 Vue 应用程序的上下文中调用此函数。当然,您需要先导入它。您应该避免与 Vue 在外部脚本中管理的 DOM 元素进行交互。特别是不要使用 ID,因为 ID 在单个页面上必须是唯一的(您不能在同一页面上重复使用该组件)。如果 Vue 刚刚从 DOM 中删除了你的元素(例如路由到另一个页面),你的脚本将会崩溃。

标签: vue.js


【解决方案1】:

我看不出有什么理由——在这个例子中——为什么你想在外部 js 文件中做任何事情,为什么不直接与 dom the vue 交互——我的意思是,正确的方式? Vue 可以使用任何 v-if 或重新渲染操作来销毁或替换您的元素。如果您想直接与 DOM 交互,您可以随时使用 this.$refs 链接到您的元素,这比 querySelector thingy 要好得多。但无论如何,这是一个虚拟的例子:

// external js file - ./extfile.js
export function canvasClick(...args) {
    console.log('canvas clicked with: ', args);
}
export function button1Click(...args) {
    console.log('button1 clicked with: ', args);
}
export function button2Click(...args) {
    console.log('button2 clicked with: ', args);
}

// vue component
<template>
    <div id="canvaspage">
        <canvas id="canvas" @click="canvasAction"></canvas>
        <div id="buttonlist">
            <h5>Select your action:</h5>
            <div class="col">
                <button id="btn1" @click.prevent="button1Action">JS file custom action 1</button>
                <button id="btn2" @click.prevent="button2Action">JS file custom action 2</button>
            </div>
        </div>
    </div>
</template>

<script>
import { canvasClick, button1Click, button2Click } from './extfile';
export default {
    name: 'CanvasPage',
    methods: {
        canvasAction(event) { canvasClick(event, this) },
        button1Action(event) { button1Click(event, this) },
        button2Action(event) { button2Click(event, this) },
    }
}
</script>

【讨论】:

    【解决方案2】:

    Vue 管理的对象是根据 Vue 的生命周期创建/销毁的。这意味着您用于查询 Vue 管理的元素的任何外部代码都应该在某种程度上与 Vue 的生命周期耦合。

    这意味着,理想情况下,您应该使用 Vue 本身来添加您想要的行为。例如,您应该将所需的这个新功能添加到 Vue 组件中。这保证了更简单的设计。

    替代方案:如果 Vue 组件来自第三方,也许来自您不能指望的另一个团队,您可以将这些事件侦听器连接到 document 并检查目标的 @ 987654322@ 属性,而不是将事件侦听器直接挂钩到 canvas 元素(可能被 Vue 破坏并且挂钩丢失)。

    document.body.addEventListener('click', (event) => {
      switch (event.target.id) {
        case 'canvas':
          console.log('Canvas clicked');
          break;
        case 'btn1':
          console.log('Button 1 clicked');
          break;
        case 'btn2':
          console.log('Button 2 clicked');
          break;
      }
    }, true);
    

    这段代码很明显,如果 DOM 中有多个元素具有这些 ID,所有这些元素都会触发该代码。

    演示:

    const CanvasComponent = Vue.component('canvas-component', {
      template: `#canvas-component`,
    });
    const BlankComponent = Vue.component('blank-component', {
      template: `<div><h3>Now click back to canvas and see that the listeners still work.</h3></div>`,
    });
    
    var router = new VueRouter({
      routes: [{
          path: '/',
          component: {template: '<div>Click one link above</div>'}
        },{
          path: '/blank',
          component: BlankComponent,
          name: 'blank'
        },
        {
          path: '/canvas',
          component: CanvasComponent,
          name: 'canvas'
        }
      ]
    });
    
    var app = new Vue({
      el: '#app',
      router: router,
      template: `
      <div>
         <router-link :to="{name: 'canvas'}">canvas</router-link> |
         <router-link :to="{name: 'blank'}">blank</router-link>
         
         <router-view></router-view>
      </div>
      `
    });
    
    
    document.body.addEventListener('click', (event) => {
      switch (event.target.id) {
        case 'canvas':
          console.log('Canvas clicked');
          break;
        case 'btn1':
          console.log('Button 1 clicked');
          break;
        case 'btn2':
          console.log('Button 2 clicked');
          break;
      }
    }, true);
    <script src="//unpkg.com/vue@2.6.9/dist/vue.min.js"></script>
    <script src="//unpkg.com/vue-router@3.1.3/dist/vue-router.min.js"></script>
    
    <div id="app">
      <canvas-component></canvas-component>
    </div>
    
    <template id="canvas-component">
      <div id="canvaspage">
        <canvas id="canvas"></canvas>
        <div id="buttonlist">
          <h5>Select your action:</h5>
          <div class="col">
            <button id="btn1">JS file custom action 1</button>
            <button id="btn2">JS file custom action 2</button>
          </div>
        </div>
      </div>
    </template>

    【讨论】:

    • document.body.addEventListener('click'... 是完成项目混乱的第一步;)
    • @MaciejKwas 是的,但考虑到您不能与原始元素交互并且 vue 会破坏/重新创建它的约束,这是唯一的选择。如果还有其他可能性,我会全神贯注(老实说)。 OP 的场景很可能(考虑到链接的答案)是遗留集成的,因此必须考虑到这一点。如果没有,最好将代码直接添加到 vue 组件中,正如我在答案开头所指出的那样。
    猜你喜欢
    • 2018-03-09
    • 1970-01-01
    • 2019-08-27
    • 2021-07-14
    • 2013-03-14
    • 1970-01-01
    • 2018-06-13
    • 2015-05-08
    • 2018-04-10
    相关资源
    最近更新 更多