在 angular
中 能够经过 ComponentFactoryResolver
来动态建立 component
, 在平时使用 vue
的过程当中也没有了解到这方面的信息。因而就花时间研究了一下。javascript
Vue
的组件能够经过两种方式来声明,一种是经过 Vue.component
,另一种则是 Single File Components(SFC)
。 html
如下除非特别说明,组件都是全局注册的vue
首先来看 Vue.component
方式的。java
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>
标签就够了。web
那么经过编程方式怎么处理呢?vue-cli
在官方文档中咱们能够看到,咱们能够经过 Vue.component('component-name')
的方式来获取到 组件
。而组件实例又有 $mount
这样一个方法,官方对于 $mount
的解释以下:编程
$mount 方法有两个参数api
{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.appIf
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.ideThe method returns the instance itself so you can chain other instance methods after it.
那咱们是否能够经过这种方式来达到咱们的需求呢?
还不够!
为何?
由于 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" });
https://codepen.io/YoRolling/...
在实际工做中,大部分都是用官方的脚手架 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>
那么是否能够经过 export
出的对象来实现咱们的需求呢?
首先咱们来看,在 SFC
中, 咱们在 script 中 export
了一个对象出去,那么经过这个对象应该是能够达到要求的。
先来看看 import
以后这个对象是什么样子的。
能够发现 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 withVue.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://codesandbox.io/s/m59r3547zy
https://codesandbox.io/s/m59r...
Happy Ending。
到这里,经过编程的方式动态建立组件挂载到HTML 的两种方式就完成了。
再次感到看文档的重要性。 🤨
👻 若有错误,欢迎你们斧正!