【Vue3源码Runtime-core篇】 第二章初始化Component

第二章初始化Component

前言

在这里插入图片描述

上一篇文章讲了整个runtime-core包的核心逻辑,以及patch算法流程图
流程图: render函数内patch算法初始化组件Element的流程,这一章就开始实现整个流程,我们只要按着流程去创建函数就可以了。

案例

今天项目的结构目录为以下图所示:

在这里插入图片描述

需要新建的文件比较多

我们首先实现一个案例
\example\helloworld\index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <script src="main.js" type="moudle"></script>
</body>
</html>

\example\helloworld\main.js

import App from './App.js'

// vue3

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

\example\helloworld\App.js

export const App = {
    
    
  render() {
    
    
    return h('div','hi,'+this.msg)
  },
  setup() {
    
    
    return {
    
    
      msg:"mini-vue"
    }
  }
}

上文已经说过纯运行时的框架
用户在使用它渲染内容时,直接为Render 函数提供了一个树型结构的数据对象。这里面不涉及任何额外的步骤,用户也不需要学习额外的知识。

创建好案例文件,我们希望编写完runtime初始化组件模块,再去打开html文件时,浏览器可以识别并且渲染出"hi,mini-vue"的字符串。

createApp 、 creatVNode 、 render

createApp API

createApp API主要接受一个树形结构rootComponent参数

import {
    
     creatVNode } from './vnode'
import {
    
     render } from './renderer'


export function creatApp(rootComponent) {
    
    
  return {
    
    
    mount(rootContainer) {
    
    
      // 先转换成vnode
      // Component转换成vnode
      // 所有逻辑操作都基于vnode

      const vnode = creatVNode(rootComponent)
      render(vnode, rootContainer)
    }
  }
}

参数rootComponent接受一个树形结构的内容,也就是App.js中的内容
在这里插入图片描述

然后creatApp返回一个mount函数
在这里插入图片描述
mount函数接受一个参数rootContainer,表示根节点
也就是index.html中的<div id="app"></div> 根节点,所有VNode到时候都基于根节点开始依次往深层挂载
在这里插入图片描述

creatVNode API

生成VNode

export function creatVNode(type,props?,children?) {
    
    
  const vnode = {
    
    
    type,
    props,
    children
  }
  return vnode
}

props,children两个参数是可选的

初始化的时候只接收到了一个type也就是我们的 App常量
在这里插入图片描述

render API

这时候我们就需要新建一个renderer.ts的文件夹了
导出我们的render函数,上一章已经详细说了runtime-core的核心流程主要对是render函数的调用。在render函数中最重要的就是patch算法

export function render(vnode, container) {
    
    
  // patch
  // 递归处理
  patch(vnode, container)
}

这样写是因为抽离出patch函数后,可以方便我们递归调用patch

Patch算法

好了接下来是比较简单的一些封装,迅速过一遍,根据注释和函数名就可以知道他们的功能作用了

\src\runtime-core\renderer.js

import {
    
     createComponentInstance,setupComponent } from "./component"

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

// 抽离出patch是为了方便后续的递归处理
function patch(vnode, container) {
    
    

  // 处理组件
  processComponent(vnode, container)
}

// 处理组件的进程
function processComponent(vnode, container) {
    
    
  mountComponent(vnode,container)
}

// 挂载组件
function mountComponent(vnode,container) {
    
    
  // 获得组件实例
  const instance = createComponentInstance(vnode)
  // setup组件
  setupComponent(instance)
  // 给组件绑定effect
  setupRenderEffect(instance,container)
}

// 这里主要是为将来更新组件diff算法做铺垫的
// setup渲染并且绑定effect副作用
function setupRenderEffect(instance,container) {
    
    
  const  subTree = instance.render()

  // vnode-> patch
  // vnode -> element -> mountElement
  patch(subTree,container)
}

\src\runtime-core\component.js


// 创建组件实例
export function createComponentInstance(vnode) {
    
    
  const component = {
    
    
    vnode,
    type:vnode.type
  }
  return component
}

// 初始化组件
export function setupComponent(instance) {
    
    
  // TODO
  // initProps()
  // initSlots()

  setupStatefulComponent(instance)


}

// 设置组件状态
function setupStatefulComponent(instance) {
    
    
  const Component = instance.type

  const {
    
     setup } = Component

  if (setup) {
    
    
    const setupResult = setup()

    handleSetupResult(instance, setupResult)
  }

}

// 处理setup的结果
function handleSetupResult(instance, setupResult) {
    
    
  // function object
  // TODO funciton

  if (typeof setupResult === "object") {
    
    
    instance.setupState = setupResult
  }

  finishComponentSetup(instance)
}

// 完成组件设置
function finishComponentSetup(instance) {
    
    
  const Component = instance.render

  if(!Component.render) {
    
    
    instance.render = Component.render
  }
}

完成源码初始化组件的逻辑,可以对照着这张流程图看一看代码的运行过程:
在这里插入图片描述

流程图建议大家多看看,这样理解程序运行逻辑时会更加的透彻!!!!后面文章也会反复提到这张图。

当然第一章中我们已经说了patch算法会识别VNode类型并且执行相应的渲染逻辑,那么下一章要对代码进行正式打包,并且识别VNode类型了!

猜你喜欢

转载自blog.csdn.net/m0_68324632/article/details/129871352