无锡市网站建设_网站建设公司_悬停效果_seo优化
2026/1/2 23:21:17 网站建设 项目流程

整体流程

完整的创建与渲染流程可以分成这些阶段:

  1. 创建 App 实例
  2. 创建根组件实例
  3. 设置响应式状态
  4. 创建渲染器(Renderer)
  5. 挂载 Mount
  6. vnode -> DOM 渲染
  7. 数据变更触发更新
  8. 重新渲染 / diff / patch

流程图大致如下:

createApp() ───> app.mount('#app')│                 │▼                 ▼createRootComponent    createRenderer│                 │▼                 ▼setup() / render()   render(vnode) -> patch│                 │▼                 ▼effect(fn) ────> scheduler -> patch updates

1、createApp 初始化

Vue 应用的入口通常是:

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

从源码看 createApp:

// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI(render) {return function createApp(rootComponent, rootProps = null) {const app = {_component: rootComponent,_props: rootProps,_container: null,_context: createAppContext()}const proxy = (app._instance = {app})// register global APIs// ...return {mount(container) {const vnode = createVNode(rootComponent, rootProps)app._container = containerrender(vnode, container)},unmount() { /* ... */ }}}
}

关键点:

  • createAppAPI(render) 生成 createApp 函数
  • app 内保存 _component、上下文 _context
  • app.mount 调用 render(vnode, container)

render平台渲染器 注入(在 web 下是 DOM 渲染器)。

2、createVNode 创建虚拟节点(VNode)

在 mount 前会创建一个虚拟节点:

function createVNode(type, props, children) {const vnode = {type,props,children,shapeFlag: getShapeFlag(type),el: null,key: props && props.key}return vnode
}

vnode 是渲染的基础单元:

shapeFlag 用来快速判断 vnode 类型,是内部性能优化。

3、渲染器 Renderer 初始化

Vue3 是平台无关的(runtime-core),真正依赖 DOM 的是在 runtime-dom 中。

创建 Renderer:

export const renderer = createRenderer({createElement: hostCreateElement,patchProp: hostPatchProp,insert: hostInsert,remove: hostRemove,setElementText: hostSetElementText
})

createRenderer 返回了我们前面在 createApp 中使用的 render(vnode, container) 函数。

4、render & patch

核心渲染入口:

function render(vnode, container) {patch(null, vnode, container, null, null)
}

patch 是渲染补丁函数:

function patch(n1, n2, container, parentComponent, anchor) {const { type, shapeFlag } = n2if (shapeFlag & ShapeFlags.ELEMENT) {processElement()} else if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {processComponent(...)}
}

简化为:

  • 如果是 DOM 元素 vnode → 挂载/更新
  • 如果是 组件 vnode → 创建组件实例、挂载、渲染子树

5、组件实例创建

当渲染组件时:

function processComponent(n1, n2, container, parentComponent, anchor) {mountComponent(n2, container, parentComponent, anchor)
}
function mountComponent(vnode, container, parentComponent, anchor) {const instance = createComponentInstance(vnode, parentComponent)setupComponent(instance)setupRenderEffect(instance, container, anchor)
}
  • processComponent 处理组件
  • mountComponent 挂载组件
    • createComponentInstance 创建组件实例
    • setupComponent 创建组件对象

createComponentInstance:

function createComponentInstance(vnode, parent) {const instance = {vnode,parent,proxy: null,ctx: {},props: {},attrs: {},slots: {},setupState: {},isMounted: false,subTree: null}return instance
}

实例保存基础信息,还没运行 setup。

6、 setupComponent(初始化组件)

function setupComponent(instance) {initProps(instance, vnode.props)initSlots(instance, vnode.children)setupStatefulComponent(instance)
}

内部会执行:

const { setup } = Component
if (setup) {const setupResult = setup(props, ctx)handleSetupResult(instance, setupResult)
}

setup 返回值​:

  • 返回对象 → 作为响应式状态 state
  • 返回函数 → render 函数

最终让组件拥有 instance.render

7、创建响应式状态

Vue3 的响应式来自 reactivity 包:

const state = reactive({ count: 0 })

底层是 Proxy 拦截 getter/setter:

  • getter:收集依赖
  • setter:触发依赖更新

依赖管理核心是 ​effect / track / trigger​。

8、 setupRenderEffect 与首次渲染

创建渲染器副作用,并调度组件挂载和异步更新:

function setupRenderEffect(instance, container, anchor) {instance.update = effect(function componentEffect() {if (!instance.isMounted) {const subTree = (instance.subTree = instance.render.call(proxy))patch(null, subTree, container, instance, anchor)instance.isMounted = true} else {// 更新更新逻辑}}, {scheduler: queueJob})
}

这里:

  • 创建一个 响应式 effect
  • 第一次执行 render 得到 subTree
  • patch 子树到 DOM

effect + scheduler 实现异步更新。

9、vnode-> 真实 DOM(DOM mount)

当 patch 到真正的 DOM 时,走的是 element 分支:

function processElement(...) {if (!n1) {mountElement(vnode, container)} else {patchElement(n1, n2)}
}

mountElement

function mountElement(vnode, container) {const el = (vnode.el = hostCreateElement(vnode.type))// propsfor (key in props) {hostPatchProp(el, key, null, props[key])}// childrenif (typeof children === 'string') {hostSetElementText(el, children)} else {children.forEach(c => patch(null, c, el))}hostInsert(el, container)
}

10、更新 & Diff 算法

当响应式状态改变:

state.count++

触发 setter → trigger

  • 将 effect 放入更新队列
  • 异步执行 scheduler
  • 调用 instance.update 再次 patch

更新阶段:

patchElement(n1, n2)

核心逻辑:

  1. props diff
  2. children diff
  3. unkeyed/keyed diff 算法(最小化移动)

具体见 patchChildrenpatchKeyedChildren

整体核心对象关系架构

App└─ vnode(root)└─ ComponentInstance├─ props / slots├─ setupState└─ render() -> subTree└─ vnode tree└─ DOM nodes

响应式依赖结构:

reactive state├─ effects[]└─ track -> effect└─ scheduler -> patch

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询