vue 动态组件名_通过keepalive实现了解vue组件实现原理(1)

        之前有一篇文章《vue如何通过el属性将实例注入到DOM中》分析了作为一个文本节点,vue是如何进行挂载的。本次通过一个keep-alive的例子带大家来了解vue框架组件的实现原理。例子非常简单,页面长这个样子:

2588154604992632fc4c2747cd383959.gif

代码如下:

fbff98fedf4d6a6d31323db74c7320dc.png

        通过switch按钮来使动态组件在组件A和组件B中间切换,其中组件A是一个可以输入的输入框。在A和B中间切换的过程中,通过keep-alive组件可以保留输入的内容。

        下面我们通过这个keep-alive组件是如何实现来了解vue的组件机制。以及当我们使用keep-alive的时候,应该注意哪些点。

在引入vue源码的时候,会为vue的原型引入一些原型方法,这些方法留待以后讲解。在new Vue的时候执行了vue这个构造函数,并且执行了_init方法。

d4847bf3c2de62eb4bd240b24921e6c4.png

可以在右侧看到new Vue时传入的options对象,其中components中包含的A和B组件也都是对象。在_init中对vm这个vue实例做了一系列的初始化以后,快要执行完_init时,通过vm.$mount来把实现把vm这个vue实例挂载到vm.$options.el即"#app"节点上:

4fbb10afce9683a45006612abd4516ca.png

由于是在运行时编译(生成render函数)的,上文的mount其实是先要生成render函数,再去调用通用的mount,由于通用的mount函数已经被缓存了,需要在当前实例的作用域下来调用,所以是通过call来调用,第一个参数为this。如下图:

774d5af661e611db22b46d6fda4b6720.png

在通用mount中调用mountComponent函数,先执行render函数获取vnode,然后返回vnode:

d6dbffd6514f825c124fb360d89676a4.png

下面我们来看这里是如何生成vnode的,进入render函数后可以看到编译之后的render函数其实是长这个样子,当然为了便于查看,格式是调整过的:

function anonymous() {

render函数会先从最里层开始生成vnode,在这里先来生成switch这个文本节点:

da593859d08af747d402e9f039f172a6.png

再把生成的vnode子节点作为参数传给上层,创建button节点:

3e1f8001c06c74c27e204997c10ac02d.png

在createElement函数中又调用了_createElement函数:

c4017e6eb362c9ad6d5efc1a175657c1.png

在_createElement中,判断button为保留标签,通过new VNode新建完vnode节点后返回:

071ad1de311512fd2530222b8f6c47ea.png

接着对换行空白符实例化完了一个文本节点后,就对组件A开始构造vnode节点,调用_c函数:

ab49deeae260cca74271caeb540e681f.png

这次在_createElement函数中,会通过resolveAsset方法,获取components中A组件的options对象,作为Ctor传入createComponent来构造vnode,data为构造vnode时需要的属性结构,context为当前上下文的vue实例:

f6096cdb2e8f1b34d13aa92918e9928b.png

在createComponent函数中,获取到vue构造函数后,通过extend方法得到组件A的构造函数:

4df473b313246c4c37e140c02fe77434.png

之后在组件的占位节点上安装了钩子,在patch的时候才能体现用处,而下面的new Vnode是真正来实例化出vnode节点的,注意组件vnode中的tag格式比较特殊:

82108de9272ad86ef16782e222b391da.png

下面对A组件的上一层keepalive继续调用_createElement函数,由于keepalive为内置组件,所以走到了createComponent的逻辑:

420fd25a0b765f4b435e7b8ca44dbe70.png

可以注意一下children参数为上面构造出来的A组件的vnode:

52bfde62d245bcd2313fe37c15a35554.png

在对keepalive标签调用createComponent时,还是使组建的构造函数继承了vue的构造函数:

2e52e02924849755dba66d5cd8660244.png

在源码中,我们可以看到继承的逻辑如下,先是以Vue组件实例的原型为原型,赋给子组件初始化函数的原型。再把初始化函数挂到了子组件实例原型的构造函数上,这个逻辑在后面初始化子组件的时候会用到。

2d7cb63286f8f55b98d570f57ef17aa8.png

在createComponent中,接下来安装钩子和实例化vnode并返回,注意组件vnode下面children属性为undefined,但是componentOptions中有children属性:

740e44c7f8822429555aa9a6c82456ed.png

下面在render函数中走到了对div节点构造vnode了,由于是保留标签名,在_createElement中直接调用new VNode:

048d7bb85227783d7839a879ee0be5a3.png

总体执行完render函数,即可得到tag为div的vnode,之后返回vnode:

46ab83cf111a1ed387092889774ce8cc.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值