zoukankan      html  css  js  c++  java
  • vue源码学习

    new Vue发生了什么

    此处只针对最简单基础的new Vue过程,一般项目中采用.vue单文件组件的形式开发,下面会介绍

    对于 runtime+compile 版本:

    1. 初始化一个 vue 实例的一系列相关环境(watcher,lifecycle, methods等等),
    2. compile:将 template (若有)转化成 render,在 render 过程中每一个模板节点都会生成对应的 _c,也就是执行 createElement 函数
    3.  给实例注册一个渲染 Watcher,渲染 watcher 拥有一个回调,该回调函数会在初始化和每次 vm 实例更新时触发,其中初始化的时候包含下面两步骤:
    4. 利用 render 函数生成 vnode。 从根 vnode开始创建(处理边界条件包括 textVnode,emptyVnode 等等),摊平所有 children vnode,children 拍平成一维数组是为了建立好 tree 的数据结构,因为对于 tree 来说,每个节点的 children 就是一维数组。最终创建成一个 vnode tree。
    5. 开始执行 patch 过程,从根 vnode 起开始创建真实 DOM,递归一整个 vnode tree,递归到最底层的时候开始将 vnode->el 插入到 parent vnode->el。patch 的递归过程是一个自上 而下的过程,但是插入到 DOM 节点的顺序是自下而上,也就是子节点先插入,父节点后插入。 也就是当每一个真实 DOM  插入到父亲 DOM 节点的时候,当前这个 DOM 节点会 是一个构建好的 DOM tree。

    整个组件patch流程图及总结

    1. 从vm._render函数开始,本质是执行createElement的过程,其中tag为App组件导出的对象,所以执行createComponent,传入tag
    2. createComponent过程对tag进行extend处理,返回组件构造器,给data注册hooks (后面用来组件实例化),创建组件vnode,传入data, 使用componentOptions来保存构造器,tag等等,返回App组件vnode
    3. 回到_render函数, 给App组件vode设置parent属性,此时是undefined,再执行vm._update方法
    4. vue实例绑定 _vnode 属性,指向App组件vnode(占位vnode),执行vm._patch, vnode为组件App vnode
    5. Vue实例patch, 此处其实是进入了createComponent,执行 组件 vnode 的 init hook
    6. init hook中, 组件vnode实例化,执行构造器的init方法,本质是vm._init, 只是vm指向组件实例
    7. 组件实例_init 过程, 执行initInternalComponent ,初始化组件实例的$options,parent指向 vue实例,_parentNode指向组件vnode
    8. 组件实例初始化生命周期,$parent 指向 vue实例,且 添加自身到 vue实例 children,完成父子关系绑定
    9. 组件实例化完成,实例保存在组件vnode的componentInstance,组件实例执行$mount 挂载
    10. 由于vue-loader编译完成已经有了render函数,执行 _render过程,创建组件实例vnode(渲染vnode)
    11. _render过程, vm.vnode=vm.vnode = vm.vnode=vm.options._parentNode ,将占位vnode保存在 组件实例vm的$vnode
    12. 其实组件实例的render函数中,tag为App组件的根节点div,这里直接创建普通节点vnode
    13. 执行组件实例 _update , vm._vnode = vnode 将渲染vnode保存在 _vnode属性,执行组件实例 _patch
    14. 普通节点,直接进入createElm 过程,创建真实dom保存到渲染vnode的elm,创建子节点,递归执行createElm
    15. 其中遇到helloworld组件又会执行createComponent,创建helloworld组件的实例,又回到了步骤5,由于helloworld中只有普通节点,patch的结果是在helloworld组件的渲染vnode中绑定了helloworld组件的真实dom(根节点和children),在init hook 完成时,会在app组件根节点下插入 helloworld 根节点dom
    16. app组件渲染vnode patch 完成,返回 vnode.elm
    17. app组件实例KaTeX parse error: Expected 'EOF', got ',' at position 16: el = vnode.elm,̲ app组件占位vnode i…el 挂载到 组件vnode的elm下
    18. 此时将 占位vnode的elm插入到 body 中, 此时视图渲染出来了,执行后面的逻辑,删除旧的div#app节点,Vue实例的patch过程完成,vm.$el = vnode.elm, 整体流程完成

    其实就是深度递归的一个挂载过程: 从最外层Vue实例,再到App组件实例,再到helloworld组件实例,helloworld实例内部DOM节点创建完成后,helloworld组件就完成了,然后就是将helloworld 的根节点挂载到 App组件根节点,App组件根节点挂载完成后,就插入到body节点下,然后移除原来的div#app。需要注意老师一开始提到的占位vnode和渲染vnode。分别是用$vnode 和 _vnode保存的。 另外 activeInstance 表示当前正在init的实例,可能是vue实例,也可能是组件实例,会在创建组件实例时注册到后面的组件实例的 $parent, 形成实例间的父子关系

    1、parent:当前子组件的父vm的实例(当前激活的组件实例)
    2、_parentVnode:占位符vnode
    3、activeInstance:当前vm的实例
    4、实例下的 $children 存储的是所有子组件 vm 实例
    5、实例下的 $parent 存储的是父组件 vm 实例
    6、实例下的 $vnode 属性就对应每个组件在父组件中的占位符 vnode,因此对于根来说 $vnode 就是 null,占位符 vnode 的主要属性都在 componentOptions 下。
    7、实例下的 _vnode 属性就是对应每个组件下的实际渲染 root vnode(该 vnode 含一维数组 children 属性,递归构建成 vnode tree,其中对于组件将会采用占位符 vnode)。

     
  • 相关阅读:
    Balance的数学思想构造辅助函数
    1663. Smallest String With A Given Numeric Value (M)
    1680. Concatenation of Consecutive Binary Numbers (M)
    1631. Path With Minimum Effort (M)
    1437. Check If All 1's Are at Least Length K Places Away (E)
    1329. Sort the Matrix Diagonally (M)
    1657. Determine if Two Strings Are Close (M)
    1673. Find the Most Competitive Subsequence (M)
    1641. Count Sorted Vowel Strings (M)
    1679. Max Number of K-Sum Pairs (M)
  • 原文地址:https://www.cnblogs.com/ltog/p/14363339.html
Copyright © 2011-2022 走看看