runtime-core初始化核心流程

本文深入剖析Vue.js的`runtime-core`初始化过程,从main.js和App.js开始,详细解释createApp函数如何创建虚拟节点和渲染函数。接着探讨vnode的创建、shapeFlag的类型判断以及组件实例对象的构建。在setup component阶段,介绍了props和slots的处理,以及setup函数的执行逻辑。文章还揭示了如何通过effect包裹组件实例的更新,并利用patch函数将虚拟节点转化为真实DOM。最后,讨论了element类型的处理流程,以及如何处理children,确保视图正确渲染。
摘要由CSDN通过智能技术生成

首先从我们的main.js入手

// example文件夹  index.html main.js App.js 
import {createApp} from '../../lib/guide-mini-vue.esm.js'
import {App} from './App.js'

const rootContainer = document.querySelector('#app')
createApp(App).mount(rootContainer) 

App.js

import {h} from '../../lib/guide-mini-vue.esm.js'
export const App = {
    name:"App",
    render(){
        return h('div',{tId:1},[h("p",{},"主页")])
    },
    setup(){}
} 

导入的createApp是利用rollup打包库中的代码生成的lib文件夹中引入的看看我们的createApp函数中做了什么

import { createVNode } from "./vnode";
// render
export function createAppAPI(render){
    return function createApp( rootComponent){
        return {
            // 接受一个根容器
            mount(rootContainer){
                // 在vue3都会将所有的元素转换成虚拟节点
                // 所有的逻辑操作都会基于vnode来执行
                const vnode = createVNode(rootComponent);
                render(vnode,rootContainer)                
}}}} 

首先会基于我们传入的App组件创建一个虚拟节点,可以先展示下生成的虚拟节点的结构

Object{
    children:undefined,
    component:null,
    el:null,
    key:null,
    props:{},
    shapeFlags:4,
    type:{name:'App',setup:fn,render:fn}
} 

这个对象中的type其实就是我们在App传入的结构,最终会通过template编译成我们的渲染函数

 h('div',{tId:1},[h("p",{},"主页")]) 

h函数主要是用来创建我们的虚拟节点,第一个参数是我们的type节点类型,第二个是props,第三个是children

runtimecore-初始化.jpg 我们可以先了解vnode的创建函数,可以看到我们在vnode上挂载了我们常见的几个重要的属性,其中还涉及到了对我们的shapeFlag的操作

export function createVNode(type,props?,children?){

     const vnode = {
        type,
        props,
        children,
        component:null,
        key:props && props.key,
        shapeFlag:getShapeFlag(type),
        el:null
    }
    // children
    if(typeof children === 'string'){
        vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN
    }else if(Array.isArray(children)){
        vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN
    }

    // 如何判定给定的参数是一个slot参数 
    // 必须是一个组件节点 并且它的children必须是一个Object
    if(vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT){
        if(typeof children === 'object'){
            vnode.shapeFlag |= ShapeFlags.SLOT_CHILDREN
        }
    }
    return vnode

} 

进入render其实就是调用改了patch函数,通过从传入对象结构出来的type来根据不同的类型执行不同的流程

function render(vnode,container){
        // 构建patch方法 方便后续的递归
        patch(null,vnode,container,null,null)
}
// 改为接受 两个虚拟节点 n1 表示之前的虚拟节点 n2表示最新的虚拟节点
function patch(n1,n2,container,parentComponent,anchor){
    const {type,shapeFlag} = n2
    // 增加一种类型只渲染我们的children
    // Fragment => 只渲染我们的children
    switch (type) {
        case Fragment:
            processFragment(n1,n2,container,parentComponent,anchor)   
            break;
        case Text:
            processText(n1,n2,container)   
        break;
        default:     // vnode => flag 我们当前虚拟节点的类型都称之为我们的flag
        // 比如我们的字符串就作为元素来对待
        // if(typeof vnode.type === 'string'){
        if(shapeFlag & ShapeFlags.ELEMENT ){ 
            // 上面的判断可以使用位运算符来进行替换
            // 当虚拟节点的类型是一个字符串时,就作为一个元素节点
            processElement(n1,n2,container,parentComponent,anchor)
            // isObject(vnode.type) 同样进行替换
        }else if(shapeFlag & ShapeFlags.
Uncaught runtime errors: × ERROR Cannot read properties of undefined (reading 'forEach') TypeError: Cannot read properties of undefined (reading 'forEach') at Proxy.getAllTotal (webpack-internal:///./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/Cart.vue?vue&type=script&lang=js:22:17) at Proxy.created (webpack-internal:///./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/Cart.vue?vue&type=script&lang=js:16:10) at callWithErrorHandling (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:285:32) at callWithAsyncErrorHandling (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:293:17) at callHook (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:3305:3) at applyOptions (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:3229:5) at finishComponentSetup (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:6496:5) at setupStatefulComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:6424:5) at setupComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:6363:36) at mountComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4970:7)
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值