如何以编程方式间接创建Vue组件

时间:2018-02-18 21:11:01

标签: javascript vue.js

我尝试以编程方式将组件添加到我的Vue单个文件组件中的页面,如果您知道自己想要提前做什么,该组件可以很好地工作。在我的例子中,组件及其布局将通过JSON接收,并且我试图动态创建它们。下面你可以看到我喜欢做类似eval之类的事情,但遗憾的是,这对于未实例化的对象并不起作用。下面的代码通过硬编码值进行了简化,以获得重点。

<template>
  <div id="app">
    <h2>Static template:</h2>
    <InputTemplate type="text"></InputTemplate>
    <h2>Dynamically inserted:</h2>
    <div ref="container">
      <button @click="onClick">Click to insert</button>
      <br/>
    </div>
  </div>
</template>  

<script>
import Vue from 'vue'
//the component I'd like to create
import InputTemplate from './components/InputTemplate.vue'

export default {
  name: 'app',
  components: { InputTemplate },
  methods: {
    onClick() {
      //I'd like to do something like this, but eval doesn't work like this
      var ComponentClass = Vue.extend(eval('InputTemplate'))
      var instance = new ComponentClass({
        propsData: {type: 'text' }
      })
      instance.$mount()
      this.$refs.container.appendChild(instance.$el)
    }
  }
}
</script>

我在下面放了一个帮助函数,取代了eval并起作用,但对于解决方案来说感觉有点不合适。它还需要为每个添加的新组件进行大量维护。有更好的方法吗?

returnComponent(componentString){
      if(componentString === 'InputTemplate'){
        return InputTemplate;
      }
    }

2 个答案:

答案 0 :(得分:2)

事实证明,Vue有<component :is="yourComponentType">,如果你将它扔进v-for循环,它就完全符合我的希望。 Documents here.

答案 1 :(得分:0)

您可以使用Async components通过API检索组件。

我已经通过Axios使用GraphQL进行了测试,但它可以与任何REST服务一起使用。

主要组件如下:

<template>
  <div>
    <h1>Test page</h1>
    <div><button @click="clicked = true">Load component</button></div>
    <async-component v-if="clicked" />
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      clicked: false,
    };
  },
  components: {
    'async-component': () => axios.post('http://localhost:5000/graphql', { query: `
      {
        asyncComponentByRowId(rowId: 1) {
          component
          content
        }
      }
    `,
    }).then((response) => {
      const comp = response.data.data.asyncComponentByRowId.content;
      // eval can be harmful
      return eval(`(${comp})`);
    }),
  },
};
</script>

检索到的组件采用以下格式:

{
  "data": {
    "asyncComponentByRowId": {
      "component": "my-async-component",
      "content": "{\r\n\ttemplate: '<div>{{ msg }}</div>',\r\n\tdata: function() {\r\n\t\treturn {\r\n\t\t\tmsg: 'Async component works!'\r\n\t\t};\r\n\t}\r\n}"
    }
  }
}

解码的data.asyncComponentByRowId.content属性是表示JavaScript对象的字符串:

{
  template: '<div>{{ msg }}</div>',
  data: function() {
    return {
      msg: 'Async component works!'
    };
  }
}

按下该按钮后,组件将在从API异步下载后显示。

唯一的问题是我正在使用eval来解码对象。

结果:

Async component screenshot