Vue VNode原理分析

1. VNode是什么及其作用

使用js对象来描述真是DOM,把DOM的标签,属性,内容都变成对象的属性。模板编译整个过程就是将template描述成VNode,经过一系列操作形成真实DOM,它的好处有两点

  1. 兼容性强,不受执行环境的影响。VNode因为是js对象,不管是Node环境还是浏览器环境,都可以统一操作,从而获得了SSR,原生渲染等能力
  2. 减少DOM操作,任何页面的变化,都是用VNode进行操作对比,只需要在最后一步挂载更新DOM即可

2. VNode如何生成

Vue内部,有一个专门的VNode类来实现VNode

function VNode(
    tag, data, children, 
    text, elm, context, 
    componentOptions
) {    
    this.tag = tag; // 标签名
    this.data = data;    
    this.children = children; // 子元素
    this.text = text; // 文本内容
    this.elm = elm; // Dom 节点
    this.context = context;    
    this.componentOptions = componentOptions;    
    this.componentInstance = undefined;    
    this.parent = undefined;    
    this.isStatic = false; // 是否静态节点
    this.isComment = false; // 是否是注释节点
    this.isCloned = false; // 是否克隆节点
};

比如下面这段html会生成如下的VNode

<div class="parent">1111</div>
// 生成如下VNode
{
    tag: 'div',
    data: {
        staticClass: 'parent'
    },
    children: [{
        tag: undefined,
        text: '1111'
    }]
}

3. VNode存放了什么信息

  1. data data内部存储了节点的属性,class, style, 存储了绑定的事件
  2. elm 真实DOM节点,生成VNode时并不存在真实DOM
  3. context 渲染模板的上下文对象
  4. isStatic 是否是静态节点,当一个节点被标记为静态节点时,说明这个几点可不用去更新它了。当数据发生变化时,可以忽略对比
  5. parent 组件的外壳节点
  6. componentInstance 组件生成的实例
  7. componentOptions 这里用来存储父子组件通信的参数

4. VNode如何生成

在初始化选项,解析完模板之后,就需要挂载DOM了。此时就需要生成VNode了。挂载 DOM 第一步,就是先执行渲染函数,得到整个模板的 VNode

function (){ 
    with(this){  
        // _c函数的作用就是返回VNode
        return _c('div',{attrs:{"href":"xxxx"}},["1111"]).
    } 
}
vm._c = function(a, b, c, d) {    
    return createElement(vm, a, b, c, d, false);
};
function createElement(
    context, tag, data, 
    children, normalizationType
) {    
    var vnode;    
    if (tag是正常html标签) {
        vnode = new VNode(
            tag, data, children, undefined, 
            undefined, context
        );
    } 
    else if (tag 是组件) {
        vnode = createComponent(
            Ctor, data, context, 
            children, tag
        );
    }   
    return vnode
}

正常标签和组件会走不同的流程,如果是标签,那直接新建VNode, 如果是组件,需要调用createComponent

function createComponent(
    Ctor, data, context, 
    children, tag
) {    
    // extractPropsFromVNodeData 作用是把传入data的 attr 中属于 props的筛选出来
    var propsData = extractPropsFromVNodeData(data, Ctor, tag);    
    var vnode = new VNode(
        ("vue-component-" + (Ctor.cid) + tag),
        data, undefined, undefined, undefined,
        context, {            
            Ctor: Ctor, 
            // 父组件给子组件绑定的props
            propsData: propsData, 
            // 父组件给子组件绑定的事件
            listeners: listeners, 
            tag: tag,            
            children: children
        });    
    return vnode

}

5.VNode存放在哪

  1. _vnode 存放当前节点的VNode,也就是可以通过这个VNode直接映射成当前真实DOM,主要作用是用来对比更新,当数据变化,会生成一个新的VNode,新的VNode和这个_node做对比。
  2. $vnode 只有组件实例才有,因为 $vnode 存放的是外壳节点,页面实例中是不存在 $vnode 的
function updateChildComponent(
    vm, parentVnode
) {
    vm.$options._parentVnode = parentVnode;
    vm.$vnode = parentVnode; 
    if (vm._vnode) {
        vm._vnode.parent = parentVnode;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值