vue组件初始化方法(vue组件实现原理)

之前文章分析过,createApp 方法执行完后,会赋值给 app,而 app 里 mount 方法是 vue 的挂载方法。

组件渲染、proxy 代理都在这个方法里面。

const { mount } = app//重写 mount 方法app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {  //先清空挂载标签下的内容  container.innerHTML = \\\'\\\'  //执行 mount 方法  const proxy = mount(container)  //返回 proxy  return proxy}
代码位置:packages/runtime-dom/src/index.ts
看下 mount 里面执行的是什么。
    mount(rootContainer: HostElement, isHydrate?: boolean): any {  if (!isMounted) {    const vnode = createVNode(      rootComponent as ConcreteComponent,      rootProps    )    //渲染vnode,挂载到页面指定的 demo 上    render(vnode, rootContainer)    //设置为 true     isMounted = true    return vnode.component!.proxy  }else{    //...  }}
    代码位置:packages/runtime-core/src/apiCreateApp.ts
    方法里先通过 isMounted 来判断是否加载过,默认为 false。如果没有挂载过,需要执行 createVNode 方法去创建 VNode,接着会进入 render 方法,并且经过各种周转来到 mountComponent 方法:
    const render: RootRenderFunction = (vnode, container) => {  //执行 patch 方法    patch(container._vnode || null, vnode, container)}//通过 patch 方法跳转到 过程组件processComponent(n1,n2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)//通过过程组件,跳转到挂载组件方法mountComponent(n2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)
    代码位置:packages/runtime-core/src/renderer.ts
    const mountComponent: MountComponentFn = (initialVNode,container,anchor,parentComponent,parentSuspense,isSVG,optimized) => {  //实例化组件  const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(    initialVNode,    parentComponent,    parentSuspense  ))  //设置组件  setupComponent(instance)}
    进入 mountComponent 方法先去实例化组件,调用 createComponentInstance 方法创建组件实例,并赋值给 instance。
      export function createComponentInstance(  vnode: VNode,  parent: ComponentInternalInstance | null,  suspense: SuspenseBoundary | null) {  //VNode 类型  const type = vnode.type as ConcreteComponent  // inherit parent app context - or - if root, adopt from root vnode  //继承父组件实例的 appContext ,如果是根组件,则从根 VNode 中取  const appContext =    (parent ? parent.appContext : vnode.appContext) || emptyAppContext  //初始化当前组件实例  //实例中添加了很多属性,uid、vnode、数据、是否挂载、是否卸载、生命周期等等...  const instance: ComponentInternalInstance = {    uid: uid++,    vnode,    // state    ctx: EMPTY_OBJ,    data: EMPTY_OBJ,    props: EMPTY_OBJ,    // lifecycle hooks    isMounted: false,    bc: null,    c: null,    bm: null,    ...  }  //声明是否是根组件  instance.root = parent ? parent.root : instance  //派发事件  instance.emit = emit.bind(null, instance)  return instance}
      代码位置:packages/runtime-core/src/component.ts
      createComponentInstance 方法就去初始化组件实例,在实例中,添加了很多属性:uid、vnode、data、props、isMounted、bc、c、m 等等。
      添加完属性,去判断是否是根组件,并且随后派发事件,最后返回当前实例。
      回到 mountComponent 方法,继续执行 setupComponent(instance) 设置组件方法。
      export function setupComponent(  instance: ComponentInternalInstance,  isSSR = false) {  //解构数据和子组件和状态  const { props, children, shapeFlag } = instance.vnode  //判断是否是有状态的  const isStateful = shapeFlag & ShapeFlags.STATEFUL_COMPONENT  //初始化 props 和 slots  initProps(instance, props, isStateful, isSSR)  initSlots(instance, children)  //根据 isStateful 来创建有状态的组件  const setupResult = isStateful    ? setupStatefulComponent(instance, isSSR)    : undefined  isInSSRComponentSetup = false  // 并返回结果  return setupResult}
      前面已经生成过组件实例了,在 setupComponent 方法里解构实例,获取到 props、children、shapeFlag 等数据。
      初始化 props 和 slots,然后再根据 shapeFlag 来判断组件是否有状态,去生成有状态组件和无状态组件。
      继续深入 setupStatefulComponent 状态组件方法。
      function setupStatefulComponent(  instance: ComponentInternalInstance,  isSSR: boolean) {  //渲染代理的属性访问缓存  instance.accessCache = Object.create(null)  instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)  const { setup } = Component  if (setup) {    const setupContext = (instance.setupContext =      setup.length > 1 ? createSetupContext(instance) : null)
      currentInstance = instance pauseTracking() resetTracking() currentInstance = null //... //处理 setup 结果 handleSetupResult(instance, setupResult, isSSR) } else { //完成组件 设置 finishComponentSetup(instance, isSSR) }}
      setupStatefulComponent 方法里属性的访问做一层代理,并且对 instance.ctx 做 new Proxy 封装,根据 setup 参数的长度去判断,如果大于 1 ,就去创建 setupContext 的渲染上下文。
      handleSetupResult 方法去处理 setup 的结果,并且方法里执行 finishComponentSetup 完成组件设置。
      这就是组件渲染的大概逻辑,回到 mount 方法,把 isMounted 更改为 true ,组件初始化、挂载就完成了。
      点击关注公众号,查看更多 Vue 的内容

      图片授权基于 www.pixabay.com 相关协议

      原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34629.html

      (0)
      小道研究's avatar小道研究
      上一篇 2024年4月15日 上午7:31
      下一篇 2024年4月15日 上午7:33

      相关推荐

      发表回复

      您的邮箱地址不会被公开。 必填项已用 * 标注