Vue3核心运行时之runtime-core

在 Vue3 的源码中,@vue/runtime-core 是整个框架的运行时的核心。它不直接操作DOM,通过@vue/runtime-dom实现vnode的创建、对比与更新。
本文主要基于runtime-core的核心流程,包括组件的初始渲染流程与更新等简要实现机制。

一、runtime-core作用

runtime-core = 平台无关的 VNode 调度器 + 组件生命周期管理
1.对比新旧虚拟 DOM,决定如何更新
2.管理组件实例的创建、渲染与更新

二、从 createApp 到 render

在vue日常开发中,入口文件通常会有这段创建应用实例的代码:

createApp(App).mount('#app')

createApp是vue内部渲染器创建的一个函数,接收一个根组件后进行mount,实现如下:

createRenderer(options) //创建渲染器
// runtime-core 内部
//options 包含runtime-dom平台操作接口(如 insert, createElement, patchProp)等
//返回 { render, createApp }
export function createRenderer(options) {
  return createBaseRenderer(options)
}
export function createBaseRenderer(rendererOptions) { // 渲染时所到的api
    const render = (vnode,container) =>{ // 核心渲染方法
		// 将虚拟节点转化成真实节点插入到容器中.....
    }
    return {
        createApp:createAppAPI(render)
    }
}
//createAppAPI实现
let uid = 0
export function createAppAPI(render) {
    const createApp = (rootComponent, rootProps = null) => {
    const app = {
      _uid: uid++,
      _component: rootComponent,
      _props: rootProps,
      _container: null,
    //   _context: context,
      _instance: null,

      mount(rootContainer){
        const vnode = createVNode(rootComponent, rootProps)
        render(vnode, rootContainer)
        app._container = rootContainer
      }
    }
    return app
}
    return createApp
}




//createApp 返回应用实例
const app = createApp(rootComponent)
app.mount(container)

//mount 最终调用 render(vnode, container)

//render 启动首次渲染
function render(vnode, container) {
  patch(null, vnode, container) // 首次挂载:oldVNode 为 null
}

三、patch 函数

patch(n1, n2, container) 是 runtime-core 实现元素或组件挂载和比对的重要函数

if (n1 === n2) return // 相同节点,跳过

if (n1 && !isSameVNodeType(n1, n2)) {
  // 类型不同:卸载旧节点,挂载新节点
  unmount(n1)
  n1 = null
}
// 根据 n2 类型分发处理
switch (n2.type) {
  case Text: processText(n1, n2, container); break
  case Comment: processCommentNode(...); break
  default:
    if (shapeFlag & ELEMENT) processElement(...)
    else if (shapeFlag & COMPONENT) processComponent(...)
}
//关键思想:  
n1 == null时挂载(mount)  
n1 存在进行更新(update)

四、元素节点和组件处理

//处理元素节点:processElement
挂载:mountElement
创建真实元素:hostCreateElement
设置属性:hostPatchProp
插入容器:hostInsert
更新:patchElement
所有 hostXXX 操作均由 runtime-dom 提供,runtime-core 只调用接口。
//组件节点(processComponent)
//挂载(n1 == null)
mountComponent(n2, container) {
  const instance = createComponentInstance(n2)
  setupComponent(instance)        // 执行 setup()
  setupRenderEffect(instance)     // 创建渲染 effect!
}

//更新(n1 存在):
updateComponent(n1, n2) {
  if (shouldUpdateComponent(n1, n2)) {
    instance.next = n2           // 标记新 vnode
    instance.update()            // 触发 effect 重新执行
  }
}

五、组件自动更新简化实现版

//setupRenderEffect是组件实现自动更新的一个重要函数:

function setupRenderEffect(instance) {
  instance.update = effect(() => {
    if (!instance.isMounted) {
      const subTree = instance.render()
      patch(null, subTree, container)
      instance.isMounted = true
    } else {
      // 更新:render 新子树与旧子树 diff
      const nextTree = instance.render()
      patch(instance.subTree, nextTree, container)
      instance.subTree = nextTree
    }
  }, {
    scheduler: queueJob // 异步更新队列
  })
}

当ref 或 reactive 数据变更时会trigger找到依赖的 effect(即 instance.update),调用scheduler(异步批量更新),effect重新执行后调用render()再进行patch子树

六、总结

runtime-core不直接处理DOM操作,只通过runtime-dom对应方式处理vnode的实现,并贯穿应用实例的创建到卸载整个生命周期流程,本文主要基于runtime-core的核心实现流程,在具体应用包括组件数据渲染,响应式数据更新等一系列流程后续会进行更新。好了,今天就到这里,欢迎有问题的小伙伴一块交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值