本文是介绍独立组件开发的系列文章的第三篇。
第一篇文章: Vue独立组件开发: prop event slot;
第二篇文章:Vue 独立组件开发:不一样的组件通信方式;
在vue
项目中,组件一般都是静态的写在template
标签里面,比如:
<template>
<div>
<my-component></my-component>
</div>
</template>
渲染时,自定义标签my-component
就会被替换为组件的内容,在哪写的组件标签,就会在哪里被替换。
换句话说,常规的组件使用方式,只能在规定的地方渲染组件。但是,在下面的两种场景中就比较局限了:
场景一:实现类似原生 场景二:组件的模板是通过调用接口从服务端获取的,需要动态渲染组件; 一般来说,在我们访问页面时,组件就已经渲染就位了,对于场景一,其实并不陌生,在 因此,对于这两种场景, 从源码中,可以非常看清楚子类的构造函数 在 我们首先看一下 同样地,组件的创建过程也是一样的。它的参数跟 针对上面的场景,就可以这样写: 这一步创建了一个构造器,这个过程也可以解决异步获取 这一步,我们调用了 最后,通过 实现同样的效果,除了用 这样既可以使用 渲染后,如果想操作 因为我们是通过 需要注意的是,我们是用 这两个 在多数情况下,我们只关注在业务层,并使用现成的组件库,所以使用这两个window.alert()
的提示框组件,它的位置是在 下,而非
jQuery
时代,通过操作 DOM,很容易就能实现,当然你也可以这么做,但是这不是 Vue
推荐的做法,既然使用 Vue
了,就应该用 Vue
的思路来解决问题。对于场景二,组件的渲染是异步的,预先不知道模板是什么。Vue.extend
和 vm.$mount
语法就派上用场了。Vue.extend
和 vm.$mount
的用法Vue.extend
的作用,就是基于 Vue
构造器,创建一个 子类构造器VueComponent
,我们看下它的源码:// Vue的构造函数
function Vue() {
this._init(options)
}
// Vue.extend创建组件的构造函数,它继承于Vue
Vue.extend = function (extendOptions) {
...
const Super = Vue
// 组件构造函数
const Sub = function VueComponent (options) {
this._init(options)
}
// 组件构造函数的原型指向Vue的原型,实现继承
Sub.prototype = Object.create(Super.prototype)
// 把组件构造函数的constructor重新指向组件构造函数
Sub.prototype.constructor = Sub
...
return Sub
}
VueComponent
继承于父类Vue
。Vue
中,组件并不是Vue
实例,组件的构造是VueComponent
,两者并不相同,而是一个继承关系,切记切记。Vue
实例的挂载过程:首先通过new Vue
实例化一个Vue
实例,实例上有个$mount
方法,调用$mount
方法,传入要挂载的dom节点,进行挂载。var app = new Vue({
render: h => h(App)
}).$mount('#app')
new Vue
的基本一样,但 data
要跟组件一样,是个函数,再配合 $mount
,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body
。import Vue from 'vue'
const ConfirmComponent = Vue.extend({
template: '
template
模板的问题,下面要手动渲染组件,并把它挂载到 body
下:const component = new ConfirmComponent().$mount();
$mount
方法对组件进行了手动渲染,但它仅仅是被渲染好了,也就是把组件内容转化为了真实的DOM
节点,但并没有挂载到节点上,也就显示不了组件。此时的 component
已经是一个标准的 Vue 组件实例,因此它的 $el
属性也可以被访问,也就是组件对应的真实DOM赋值给了$el
属性。appendChild
方法挂载到body
上。当然,除了 body
,你还可以挂载到其它节点上。document.body.appendChild(component.$el);
$mount
也有一些快捷的挂载方式,以下两种都是可以的:// 在 $mount 里写参数来指定挂载的节点
new ConfirmComponent().$mount('#app');
// 不用 $mount,直接在创建实例时指定 el 选项
new ConfirmComponent({ el: '#app' });
Vue.extend
外,也可以直接创建 Vue
实例,并且用一个 Render
函数来渲染一个 .vue
文件:import Vue from 'vue';
import Notification from './notification.vue';
const props = {}; // 这里可以传入一些组件的 props 选项
const Instance = new Vue({
render (h) {
return h(Notification, {
props: props
});
}
});
// 生成真实DOM
const component = Instance.$mount();
// 把真实DOM挂载到body节点上
document.body.appendChild(component.$el);
.vue
来写复杂的组件(毕竟在 template
里堆字符串很痛苦),还可以根据需要传入适当的 props
。Render
的 Notification
实例,也是很简单的,只需要找到Notification
实例即可。Vue
来实例化的,内部再通过VueComponent
来实例化了一个组件,两者就构成了父子关系,所以可以这么获取子组件的实例:const notification = Instance.$children[0];
$mount
手动渲染的组件,如果要销毁,也要用 $destroy
来手动销毁实例,必要时,也可以用 removeChild
把节点从 DOM 中移除。总结
API
如果你不对 Vue
源码有一定的了解,你可能并不能真正意义上的弄懂上面的写法。所以,我个人还是非常适当的阅读下Vue
源码。API
的情况较少。