# 30|虚拟DOM(上):如何通过虚拟DOM更新页面? 你好,我是大圣。 上一讲我们主要介绍了Vue项目的首次渲染流程,在mountComponent中注册了effect函数,这样,在组件数据有更新的时候,就会通知到组件的update方法进行更新。 Vue中组件更新的方式也是使用了响应式+虚拟DOM的方式,这个我们在第一讲中有介绍过Vue 1、Vue 2和Vue 3中更新方式的变化,今天我们就来详细剖析一下Vue组件内部如何通过虚拟DOM更新页面的代码细节。 ## Vue虚拟DOM执行流程 我们从虚拟DOM在Vue的执行流程开始讲起。在Vue中,我们使用虚拟DOM来描述页面的组件,比如下面的template虽然格式和HTML很像,但是在Vue的内部会解析成JavaScript函数,这个函数就是用来返回虚拟DOM: ```javascript

hello world

``` 上面的template会解析成下面的函数,最终返回一个JavaScript的对象能够描述这段HTML: ```javascript function render(){ return h('div',{id:"app"},children:[ h('p',{},'hello world'), h(Rate,{value:4}), ]) } ``` 知道虚拟DOM是什么之后,那么它是怎么创建的呢? ### DOM的创建 我们简单回忆上一讲介绍的[mount函数](https://github.com/vuejs/vue-next/blob/master/packages/runtime-core/src/apiCreateApp.ts#L283),在代码中,我们使用createVNode函数创建项目的虚拟DOM,可以看到**Vue内部的虚拟DOM,也就是vnode,就是一个对象,通过type、props、children等属性描述整个节点**: ```javascript const vnode = createVNode( rootComponent as ConcreteComponent, rootProps ) function _createVNode() { // 处理属性和class if (props) { ... } // 标记vnode信息 const shapeFlag = isString(type) ? ShapeFlags.ELEMENT : __FEATURE_SUSPENSE__ && isSuspense(type) ? ShapeFlags.SUSPENSE : isTeleport(type) ? ShapeFlags.TELEPORT : isObject(type) ? ShapeFlags.STATEFUL_COMPONENT : isFunction(type) ? ShapeFlags.FUNCTIONAL_COMPONENT : 0 return createBaseVNode( type, props, children, patchFlag, dynamicProps, shapeFlag, isBlockNode, true ) } function createBaseVNode(type,props,children,...){ const vnode = { type, props, key: props && normalizeKey(props), ref: props && normalizeRef(props), children, shapeFlag, patchFlag, dynamicProps, ... } as VNode // 标准化子节点 if (needFullChildrenNormalization) { normalizeChildren(vnode, children) } else if (children) { vnode.shapeFlag |= isString(children) ? ShapeFlags.TEXT_CHILDREN : ShapeFlags.ARRAY_CHILDREN } return vnode }componentUpdateFn ``` createVNode负责创建Vue中的虚拟DOM,而上一讲中我们讲过mount函数的核心逻辑就是使用setupComponent执行我们写的