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日常开发中,入口文件通常会有这段创建应用实例的代码:

javascript 复制代码
createApp(App).mount('#app')

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

javascript 复制代码
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 实现元素或组件挂载和比对的重要函数

javascript 复制代码
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)

四、元素节点和组件处理

javascript 复制代码
//处理元素节点:processElement
挂载:mountElement
创建真实元素:hostCreateElement
设置属性:hostPatchProp
插入容器:hostInsert
更新:patchElement
所有 hostXXX 操作均由 runtime-dom 提供,runtime-core 只调用接口。
javascript 复制代码
//组件节点(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 重新执行
  }
}

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

javascript 复制代码
//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的核心实现流程,在具体应用包括组件数据渲染,响应式数据更新等一系列流程后续会进行更新。好了,今天就到这里,欢迎有问题的小伙伴一块交流!

相关推荐
我是若尘14 小时前
我的需求代码被主干 revert 了,接下来我该怎么操作?
前端·后端·代码规范
魁首14 小时前
Claude Code 源码泄露的背后,到底与Codex,Gemini 有啥不一样?
前端·openai·claude
攀登的牵牛花14 小时前
程序员失业论,被 SWE-CI 一组数据打醒:真正先被替代的是低质量交付
前端·github
EstherNi15 小时前
vue3仿照elementui样式的写法,并进行校验,并且有默认值的设置
javascript·elementui
BumBle15 小时前
Vue项目中实现路由守卫自动取消Pending请求
前端
gCode Teacher 格码致知15 小时前
Javascript提高:get和post等请求,对于汉字和空格信息进行编码的原则-由Deepseek产生
开发语言·前端·javascript·node.js·jquery
竹林81815 小时前
从ethers.js迁移到Viem:我在一个DeFi项目前端重构中踩过的坑
前端·javascript
像我这样帅的人丶你还15 小时前
从交稿到甩锅预防:AI 前端流水线
前端·ai编程
想想弹幕会怎么做15 小时前
如何构建一颗可交互的ui树?
前端
程序员陆业聪15 小时前
我见过的最反直觉的 Android 架构问题:UseCase 越多,项目越烂
前端