vue3 的createApp

413 阅读2分钟

createApp实现

创建vnode const vnode = createVNode(rootComponent); 调用render渲染vnode render(vnode, rootContainer);

//核心创建app对象
const app = ensureRenderer().createApp(...args)
//重写mount方法
const { mount } = app

ensureRenderer()用于创建一个渲染器(包含平台渲染核心的js对象)对象

function ensureRenderer() {
  return (
    renderer ||
    (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  )
}

利用createRenderer创建渲染器,执行createAppAPI方法返回的函数

使用createApp方法,把app组件对象作为根组件传递给rootComponent,创建一个app对象(此时该对象已有mount方法),提供mount方法。在整个app对象创建过程,vue利用闭包和函数柯里化的技巧,保留参数。如在执行app.mount时,不需要传入渲染器render,因为在执行createAppAPI的渲染器render参数已经被保留下来。

为什么要重写mount方法

因为vue希望是支持跨平台渲染,createApp函数内部的app.mount方法是一个标准的可跨平台渲染流程。

//标准跨平台渲染
mount(rootContainer){
//创建根组件的vnode,rootComponent可以是不同类型值,web为对象,wx和app为其他值
const vnode = createVNode(rootComponent,rootProps)
//利用渲染器渲染vnode
render(vnode,rootContainer)
app._container = rootContainer
return vnode.component.proxy
}
//重写app.mount方法
app.mount = (containerOrSelector)=>{
//标准化容器
const container = normalizeContainer(containerOrSelector)
//如组件对象没有定义render函数和template模板,则取容器的innerHTML作为组件模板内容
if(!container)
return 
const component = app._component
if(!isFuunction(component)&&!component.render&&!component.template){
    component.template = contain.innerHTML
}
//挂载前清空容器内容
container.innerHTML=''
//真正挂载,走标准挂载流程
return mount(container)
}

createVNode函数

export const createVNode = function (
  type: any,
  props?: any,
  children?: string | Array<any>
) {
  // 注意 type 有可能是 string 也有可能是对象
  // 如果是对象的话,那么就是用户设置的 options
  // type 为 string 的时候
  // createVNode("div")
  // type 为组件对象的时候
  // createVNode(App)
  const vnode = {
    el: null,
    component: null,
    key: props?.key,
    type,
    props: props || {},
    children,
    shapeFlag: getShapeFlag(type),
  };

  // 基于 children 再次设置 shapeFlag
  if (Array.isArray(children)) {
    vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN;
  } else if (typeof children === "string") {
    vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN;
  }

  normalizeChildren(vnode, children);

  return vnode;
};

render渲染函数,有patch函数(1、根据vnode挂载到,2、负责新旧vnode更新到)