zoukankan      html  css  js  c++  java
  • vue2.x源码中的占位符

    vue2.x源码中的占位符

    事情的起因是我再次看了这篇掘金文章从一次 vue ssr 渲染客户端报错, 来看 ssr 客户端激活过程,里面写的在 updateClass() 中, vnode 的 tag 是 div, 而 vnode 的 elm 却是 comment. 因为 comment 节点是没有 setAttribute 方法的, 所以就报错了.让我看的不是很懂,特别是 comment 是干什么的我不是很懂,所以我搭了一个项目进行调试,理顺我不清楚的地方。

    通过本篇文章,您可以学到:

    1. 怎么搭环境调试 vue2.x 源码?
    2. 占位符是什么?有什么用?
    3. 组件更新阶段是怎么更新占位符节点的?

    环境搭建

    1.我们使用 vue-cli 搭建一个项目

    vue create test-sourcecode
    

    2.在项目里面克隆 vue 源码库

    cd test-sourcecode
    git clone git@github.com:vuejs/vue.git
    

    3.进入 vue 源码库并使用 watch 形式编译

    cd vue-dev
    npm install
    npm run dev
    

    4.回到 test-sourcecode 文件夹,加入.eslintignore文件,禁止 eslint 检查 vue 源码

    cd ..
    echo 'vue-dev' >> .eslintignore
    

    5.把项目中的import Vue from 'vue'替换为import Vue from '../vue-dev/dist/vue.js'

    6.使用npm run serve启动项目即可。在源码和项目上的改动都会有热重载效果,可以放心加console.log看输出了。

    占位符是什么?有什么用?

    我们经常在各种源码分析文章上面看到占位符节点、placeholder节点等,他们是干什么的呢?

    这里我就不贴图或者代码了,直接说了。vue 的组件在生成 vnode 的过程中,对于原生节点就直接生成 tag 为对应原生 tag 的vnode 节点,而对于组件节点就生成 tag 是vue-component-1-App的节点,这种节点就是占位符节点,或者叫 placeholder 节点。

    这种节点的作用是,只是占据一个位置而已,并不会像原生vnode节点一样会进行更新,也不会带上对应组件vnode的数据,它的更新流程是这样的,在比较新旧占位符节点进行更新的时候:

    1. 如果新旧占位符节点有不存在的,就直接创建或销毁占位符节点,同时通过创建或通过vnode hook销毁对应的组件 vnode。
    2. 如果新旧占位符节点都存在,但是不是同一个节点,就销毁旧节点,在就占位符节点的父节点下创建新占位符节点,同时创建对应的组件 vnode。
    3. 如果新旧占位符节点都存在,并且是同一个节点,则使用vnode hook更新对应的组件 vnode。

    注意:上面提到的组件 vnode 指的是,占位符对应的组件生成的组件 vnode,它才是真正控制这个组件更新的 vnode。(另外,函数式组件不会生成占位符节点,因为它没有生命周期)

    那怎么通过占位符节点找到对应的组件 vnode 呢?其实很简单,在创建占位符节点的时候,会把组件 vnode 挂载到这个占位符节点的componentInstance属性上,所以这个属性就指向了组件 vnode。

    组件更新节点是怎么更新占位符节点的

    具体的更新流程上面已经说了,总的来说,就是使用占位符节点的 vnode hook 来更新组件 vnode ,这里详细说明一下怎么用 vnode hook 来更新的

    1.判断这个节点是不是占位符节点,源码中是通过查看占位符节点有没有 hook 进行判断的,如果是的话,就进行 prepatch:

    if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
      i(oldVnode, vnode)
    }
    

    2.在进行 prepatch 的时候,会通过 componentInstance 拿到对应的组件 vnode,然后通过 updateChildComponent 方法更新组件 vnode 的props、listeners等

    prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
        const options = vnode.componentOptions
        const child = vnode.componentInstance = oldVnode.componentInstance
        updateChildComponent(
            child,
            options.propsData, // updated props
            options.listeners, // updated listeners
            vnode, // new parent vnode
            options.children // new children
        )
    },
    

    3.到这里占位符节点的任务就已经完成了,但是组件只更新了props、listeners等,然后组件自身通过props、listeners这些响应式数据,来实现自身的更新

    其它

    在看源码的时候,还是有几个小问题的,留待下次解决了:

    1. 什么是comment 节点
    2. 什么是asyncPlaceholder?
    3. 什么是static vnode?
  • 相关阅读:
    行为的封装
    分页功能-----》链表实现
    python入门教程链接
    作用域 属性链接 存储类型
    Codeforces Round #598 (Div. 3)
    CCPC2018-湖南全国邀请赛
    【洛谷P2494】 [SDOI2011]保密(分数规划+最小割)
    【洛谷P3329】 [ZJOI2011]最小割(最小割树)
    【BZOJ3716】[PA2014]Muzeum(贪心+网络流)
    【洛谷P4542】 [ZJOI2011]营救皮卡丘(费用流)
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/13944929.html
Copyright © 2011-2022 走看看