Evan You课程b站地址: https://www.bilibili.com/video/BV1rC4y187Vw?p=7&spm_id_from=pageDriver&vd_source=97f7ca7924dd57017c9bb65f9a9860a1
    三个模块:

    1. 响应式模块:创建JS对象并观察其变化
    2. 编译器模块: 将HTML模板编译成渲染函数
    3. 渲染模块: 渲染阶段(调用render返回虚拟DOM节点),挂载阶段(利用虚拟DOM调用DOM API创建页面),补丁阶段(新旧虚拟DOM比较更新变化部分到网页)

    一个组件的创建过程:先将template编译成render函数,然后响应式模块初始化响应式数据对象,接着渲染模块调用引用了响应式对象的render函数,返回虚拟DOM节点,在挂载阶段调用mount函数创建网页。当响应式模块观察到数据变化时,渲染器重新调用render函数生成新的虚拟DOM节点,然后将新旧节点发送到patch函数,比较以最小程度更新页面。

    Vue3变化:

    1. 自定义渲染器API,我们可以依赖vue3 runtime-core和自定义的渲染器API自定义渲染器。WebGL渲染器
    2. render函数

    image.png
    image.png

    功能型组件:使用渲染函数,获取插槽内容进行渲染

    1. const slot = this.$slots.default && this.$slots.default()
    2. // 作用域插槽,给default传递props
    3. const slot = this.$slots.default && this.$slots.default({...})
    4. const slot = this.$slots.default
    5. ? this.$slots.default()
    6. : []
    7. <Stack size="4">
    8. <div>hello</div>
    9. <div>hello</div>
    10. <div>hello</div>
    11. <Stack size="4">
    12. <div>hello</div>
    13. <div>hello</div>
    14. </Stack>
    15. </Stack>
    16. h('div' , { class: 'stack' } , slot.map(child => {
    17. return h('div' , { class="mt-4"} , [
    18. child
    19. ])
    20. }))

    hoist: 每次节点更新render都会重新调用,将静态节点提升到render外

    模板编译阶段的动态属性标记
    对于某个节点不必遍历整个节点对象,只需要关注动态的属性,模板编译器会做标记,这是模板相比于手写渲染函数的优点。
    image.png
    编译器:当进行动态节点的patch flag标记后,会给组件根节点openBlock,将这个flag作为一个属性添加到这个block上(动态子节点),一个额外的动态子节点扁平数组
    image.png

    使用结构指令(如v-if)的节点会将其与其子节点作为一个block,这个block跟踪其父块的所有动态子节点,依然是一个扁平数组。image.png

    事件处理程序缓存:避免了事件处理程序引起的大规模组件树的重新渲染。

    1. <div id="app"></div>
    2. <script>
    3. function h(tag, props, children) {
    4. }
    5. function mount(vnode, container) {
    6. }
    7. const vdom = h('div', { class: 'red' }, [
    8. h('span', null, 'hello')
    9. ])
    10. mount(vdom, document.querySelector('#app'))
    11. </script>

    patch方法最有意思的部分:
    the most intersting part: both oldChildren and newChildren are arrays
    internally , invue,we have two modes:
    keyed mode: the key serves as a hint about the position of a node in child list
    move the child node according to their key

    两个层次的提示优化:

    1. 跳过patch中props的比较,跳过children的比较
    2. block optimize: 直接可以跳过patch调用

    手写vue3
    https://jsbin.com/fanixek/1/edit?html,output

    除虚拟DOM外其他的编译策略:
    比如直接根据模板生成指令列表 [ appendChild , createElement , ...]