Vue 动态创建 component

Vue 动态创建 组件

Vue 的组件可以通过两种方式来声明,一种是通过 Vue.component,另外一种则是 Single File Components(SFC)

以下除非特别说明,组件都是全局注册的

Vue.component 方式

Vue.component('button-counter',{
   data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
});

在上面的代码中我们声明了一个叫做 button-counter 的组件。如果在常规情况下使用的话,只需要在页面上写对应的 <button-counter><button-counter> 标签就够了。
那么通过编程方式怎么处理呢?
在官方文档中我们可以看到,我们可以通过Vue.component(‘component-name’) 的方式来获取到 组件 (组件的构造函数)。而组件实例又有 $mount 这样一个方法,官方对于 $mount 的解释如下:

$mount 方法有两个参数

{Element | string} [elementOrSelector]
{boolean} [hydrating]
If a Vue instance didn’t receive the el option at instantiation, it will be in “unmounted” state, without an associated DOM element. vm.$mount() can be used to manually start the mounting of an unmounted Vue instance.
If elementOrSelector argument is not provided, the template will be rendered as an off-document element, and you will have to use native DOM API to insert it into the document yourself.
The method returns the instance itself so you can chain other instance methods after it.
汉译:
如果Vue实例el在实例化时没有收到选项,则它将处于“未安装”状态,没有关联的DOM元素。vm.$mount()可用于手动启动未安装的Vue实例的安装。
如果elementOrSelector未提供参数,则模板将呈现为文档外元素,您必须使用本机DOM API自行将其插入到文档中。
该方法返回实例本身,以便您可以在其后链接其他实例方法。

因为 Vue.component 返回的结果是一个 function!它返回的并不是 组件实例,而是一个构造函数。

那到这里其实我们就清楚了。 对于 Vue.component 声明的组件,我们先通过 Vue.component 获取它的构造函数,再 new 出一个组件实例,最后 通过 mount挂载到 html 上。

Vue.component("button-counter", {
  data: function() {
    return {
      count: 0
    };
  },
  template:
    '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
});

Vue.component("app", {
  data: function() {
    return {
      count: 0
    };
  },
  template:
    '<div> <h1>App Component</h1><button @click="insert">click to insert new Component</button> <div id="appId"> </div></div>',
  methods: {
    insert() {
      const component = Vue.component("button-counter");
      const instance = new component();
      instance.$mount("#appId");
    }
  }
});

new Vue({
  el: "#app"
});

SFC

实际工作中,大部分都是用官方的脚手架 vue-cli 生成项目,用的也是 SFC 这种方式。

我们的 button-counter 如果用 SFC 方式实现的话应该是这样子的:

<template>
    <button v-on:click="count++">You clicked me {{ count }} times.</button>
</template>

<script>
export default {
  name: "ButtonCounter",
  data() {
    return {
      count: 0
    };
  }
};
</script>

import 得到的对象要比我们在 组件中声明的多了一些属性和方法。

Vue.component 模式中,我们先获取到组件的构造函数,然后构造实例,通过实例的一些方法来处理数据和挂载节点。

很显然,现有数据不能满足我们。如果我们能将这个对象转化成一个组件的构造函数,那我们就可以利用上面的方案来实现我们的需求了。

那么,究竟需要怎么转换呢?
没错! 就是 Vue.extend 这个大兄 dei!我们看下官方的说明。

Create a “subclass” of the base Vue constructor. The argument should be an object containing component options.
The special case to note here is the data option - it must be a function when used with Vue.extend().
创建基本Vue构造函数的“子类”。参数应该是包含组件选项的对象。
这里要注意的特殊情况是data选项 - 使用时必须是一个函数Vue.extend()。

通过传入一个包含 Component options 的对象, Vue.extend 帮助我们创建一个 继承了 Vue constructor 的子类,也就是我们之前需要的构造函数。

好了,得到了构造函数,接下来的工作就简单了 。实例化,然后挂载。

下面就是完整的代码:

<template>
  <div id="app">
    <div>
    <img width="25%" src="./assets/logo.png">
  </div>
    <div>
    <button @click="insert">click me to insert ButtonCounter</button>
  </div>
    <div id="container"></div>
  </div>
</template>

<script>
import ButtonCounter from './components/ButtonCounter';
import Vue from 'vue';
export default {
  name: 'App',
  components: {
    ButtonCounter,
  },
  methods: {
    insert() {
      const bcConstructor = Vue.extend(ButtonCounter);//组件构造函数
      const instance = new bcConstructor();//组件实例
      instance.$mount('#container');
    },
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>    

转自:https://segmentfault.com/a/1190000015698278

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值