VUE3组件化

761 阅读3分钟

在VUE中它可以将一个大的页面拆分为多个部分,每一个部分都可以作为单独 的组件,这些组件共同组成完整的页面。组件化的实现同样需要渲染 器的支持,接下来我们看下组件化需要怎么做。

本篇的相关的解析,我们先用文字描述逻辑,然后再转换成代码实现

组件的结构

TS创建组件的definecomponent只是用来赋予类型,这里我们不关注。 实际我们定义的结构和最后解析到虚拟DOM环节时的结构是这样:

// MyComponent 是一个组件,它的值是一个选项对象 
const MyComponent = {
    name: 'MyComponent',
    // 配置时写法
    data() {
        return { foo: 1 }
    },
    //返回明确的render函数 
    render() {
        return {
            type: 'div',
            children: '文本'
        }
    }
}


// MyComponent1 是一个组件,它的值是一个选项对象 
const MyComponent1 = {
    name: 'MyComponent1',
    props: { 05 title: String 06 },
    //组合式写法
    setup(props) {
        // setup中返回的函数当render函数
        return () => {
            return {
                type: 'div',
                children: ['文本',props.title]
            }
        }
    },
    // 或者返回明确的render函数 和上面setup返回 只需要有一个就可以
    render() {
        return {
            type: 'div',
            children: '文本'
        }
    }
}

这两种写法代表了2和3 option配置式和Composition api组合式写法(这里为了方便理解,返回值直接虚拟DOM化展示了),创建的组件。

组件在虚拟DOM中类型

我们虚拟DOM篇,看到我们的虚拟DOM有:

// 该 vnode 用来描述普通标签 
const vnode = {
    type: 'div'
    // ... 
}

// 该 vnode 用来描述文本节点 
const vnode = {
    type: Text
    // ... 
}

等类型,从这里我们能想到 那肯定有type是组件的类型。

那对于组件类型的VNode它的type我们直接把存储组件的选项对 象放上去,也就是说VNode.type是一个对象时那它肯定就是有状态组件(函数组件后面讲)。

也就是说最后的使用可能是这样:

// 用来描述组件的 VNode 对象,type 属性值为组件的选项对象 
const CompVNode = {
    type: MyComponent
}
// 调用渲染器来渲染组件 
renderer.render(CompVNode, document.querySelector('#app'))

render就是我们虚拟DOM篇讲的render,renderer渲染器是为了做跨平台(这里不细讲这个)

挂载和更新函数的实现

那虚拟DOM篇我们的mountComponent和patchComponent具体实现是没写的,在这篇章我们能看到他们的实现。

首次render时那一定是挂载 mountComponent,那我们先来实现它,我们看下实现它需要几步,我们先用文字描述逻辑,然后再转换成代码。

mountComponent
  1. 首先我们要取出组件的各个属性配置,组件对象我们知道存到type上了,所以我们从type上把data函数、render函数、setup函数、props属性配置(别名propsOption)、和其他生命周期函数。
  2. 接下来就是创建组件操作了,在这之前我们先调用beforeCreate创建之前的生命周期函数
  3. 然后调用data函数获取state,这个state需要是响应式数据,所以我们用reactive包一下。
  4. 然后根据组件的props就是propsOption,和实际传递的props(vnode.props)来解析出props和attrs
  5. 然后获取一下插槽const slots = vnode.children || {};
  6. 然后我们创建模拟一个组件实例instance,存一些属性,这个组件实例属性在卸载和更新、生命周期存储等操作都会用到。
  7. instance上我们存储state和props(它通过shallowReactive变成了响应式数据,组件props变更时把它改了,如果当前组件用了它,通过这个响应式来触发组件更新),isMounted表示是否被挂载,subTree存储render函数返回的VNode,slots插槽,mounted数组存储setup中onMounted函数。
  8. 然后我们处理onMounted往实例instance上存储,因为vue组件的实例化过程也就是mountComponent是同步的,同一时间只会有一个调用,所以我们可以用一个全局变量currentInstance存一下组件实例,等setup结束后再置空,然后onMounted的实现就直接

插槽数据解析: image.png