Vue3组件渲染前的初始化过程

 更新时间:2024年07月02日 08:50:31   作者:F_Director  
Vue3 中一个组件从创建到挂在,会经过3个重点步骤:创建组件实例,设置组件实例,创建并执行带副作用的渲染函数,本文将着重讲清 创建组件实例、设置组件实例 这两个过程都做了什么,这部分逻辑很简单,但你会从中学习到 Vue 优秀的实践技巧,需要的朋友可以参考下

Vue3 中一个组件从创建到挂在,会经过3个重点步骤:

  • 创建组件实例
  • 设置组件实例
  • 创建并执行带副作用的渲染函数(render Effect)

本文将着重讲清 创建组件实例设置组件实例 这两个过程都做了什么。这部分逻辑很简单,但你会从中学习到 Vue 优秀的实践技巧。

一. 创建组件实例

这一步其实没太多可说的,只是实例化了一个初始状态的组件对象,并没有什么逻辑在里面,不过你千万别被这么庞大的信息量吓到,我们关注的是组件实例上有哪些常见的属性和方法,以及他们的维护方式。这能让我们对Vue组件信息有更多的了解。

下面是copy的源码:

function createComponentInstance (vnode, parent, suspense) {
  // 继承父组件实例上的 appContext,如果是根组件,则直接从根 vnode 中取。
  const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
  const instance = {
    // 组件唯一 id
    uid: uid++,
    // 组件 vnode
    vnode,
    // 父组件实例
    parent,
    // app 上下文
    appContext,
    // vnode 节点类型
    type: vnode.type,
    // 根组件实例
    root: null,
    // 新的组件 vnode
    next: null,
    // 子节点 vnode
    subTree: null,
    // 带副作用更新函数
    update: null,
    // 渲染函数
    render: null,
    // 渲染上下文代理
    proxy: null,
    // 带有 with 区块的渲染上下文代理
    withProxy: null,
    // 响应式相关对象
    effects: null,
    // 依赖注入相关
    provides: parent ? parent.provides : Object.create(appContext.provides),
    // 渲染代理的属性访问缓存
    accessCache: null,
    // 渲染缓存
    renderCache: [],
    // 渲染上下文
    ctx: EMPTY_OBJ,
    // data 数据
    data: EMPTY_OBJ,
    // props 数据
    props: EMPTY_OBJ,
    // 普通属性
    attrs: EMPTY_OBJ,
    // 插槽相关
    slots: EMPTY_OBJ,
    // 组件或者 DOM 的 ref 引用
    refs: EMPTY_OBJ,
    // setup 函数返回的响应式结果
    setupState: EMPTY_OBJ,
    // setup 函数上下文数据
    setupContext: null,
    // 注册的组件
    components: Object.create(appContext.components),
    // 注册的指令
    directives: Object.create(appContext.directives),
    // suspense 相关
    suspense,
    // suspense 异步依赖
    asyncDep: null,
    // suspense 异步依赖是否都已处理
    asyncResolved: false,
    // 是否挂载
    isMounted: false,
    // 是否卸载
    isUnmounted: false,
    // 是否激活
    isDeactivated: false,
    // 生命周期,before create
    bc: null,
    // 生命周期,created
    c: null,
    // 生命周期,before mount
    bm: null,
    // 生命周期,mounted
    m: null,
    // 生命周期,before update
    bu: null,
    // 生命周期,updated
    u: null,
    // 生命周期,unmounted
    um: null,
    // 生命周期,before unmount
    bum: null,
    // 生命周期, deactivated
    da: null,
    // 生命周期 activated
    a: null,
    // 生命周期 render triggered
    rtg: null,
    // 生命周期 render tracked
    rtc: null,
    // 生命周期 error captured
    ec: null,
    // 派发事件方法
    emit: null
  }
  // 初始化渲染上下文
  instance.ctx = { _: instance }
  // 初始化根组件指针
  instance.root = parent ? parent.root : instance
  // 初始化派发事件方法
  instance.emit = emit.bind(null, instance)
  return instance
}

二. 设置组件实例

这一步的重点在创建上下文代理,和执行处理setup函数的返回结果。

设置组件实例解决的问题,实际上都是组件渲染前所必须准备好的内容:

二.1 创建上下文代理

为什么需要上下文代理?可以举一个简单的例子:

<template>
  <p>{{ msg }}</p>
</template>
<script>
export default {
  data() {
    msg: 1
  }
}
</script>

为了方便维护,Vue 把组件中不同状态的数据存储到组件实例(instance)的不同的属性中,比如存储到 setupState、ctx、data、props 中。比如,msg 就被收拢到 instance.data中。

可是在模板渲染时,渲染逻辑不知道 msg 是来自 data 还是 props 亦或者是 setupState。供给用户的逻辑(比如, getCurrentInstance() api能在setup中访问到组件实例的变量和属性,但不推荐使用此api) 在访问 msg 时候也需要预先判断 msg 的溯源,然后才能决定是通过 instance.data 访问还是 instance.props 访问。这无疑增加了变量查询的负担。

为了方便使用,Vue 会直接访问渲染上下文 instance.ctx 中的属性,对instance.ctx做一层 proxy,对渲染上下文 instance.ctx 属性的访问和修改,代理到对 setupState、ctx、data、props 中的数据的访问和修改。

你需要学习的是访问组件变量时对数据集合的访问顺序,以及accessKey这样的柯里化思想。

值得注意的是,在set时,如果直接对props中的数据赋值,在非生产环境中就会产生一条警告。

创建accessKey的好处是节约了对不同上下文对象进行反复hasOwnPropety的性能损耗。

二.2 判断处理setup函数

这一步主要就是给setup注入参数,然后包了一层try...catch。然后处理setup的返回值。

为什么要包 try...catch?

笔者认为,setup 函数毕竟还是用户自己写的,难免出现逻辑错误,用 try...catch 不仅能防止程序被终止还能获取错误信息被Vue拦截处理。这是一种良好实践,在我们日常开发中,也应该考虑将暴露给用户书写的逻辑区域包一层try...catch来捕获不属于框架之内的错误。

二.3 完成组件实例设置

这一块就是在处理完setup返回结果后进行的,因为组件可能缺失render函数,用户的常用写法是template模板,且用户的编译环境可能并非是运行时编译(runtime-compiler)版本。所以这里需要统一转换为render函数的形式,以方便后面instance.update中方便拿到subTree。

这部分逻辑用一个脑图就能阐明:

以上就是Vue3组件渲染前的初始化过程的详细内容,更多关于Vue3组件初始化的资料请关注脚本之家其它相关文章!

相关文章

  • Vue Element前端应用开发之echarts图表

    Vue Element前端应用开发之echarts图表

    在我们做应用系统的时候,往往都会涉及图表的展示,综合的图表展示能够给客户带来视觉的享受和数据直观体验,同时也是增强客户认同感的举措之一
    2021-05-05
  • 全面解析Vue中的$nextTick

    全面解析Vue中的$nextTick

    这篇文章主要介绍了Vue中的$nextTick的相关资料,帮助大家更好的理解和使用vue,感兴趣的朋友可以了解下
    2020-12-12
  • 修改Vue打包后的默认文件名操作

    修改Vue打包后的默认文件名操作

    这篇文章主要介绍了修改Vue打包后的默认文件名操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • vuex数据持久化的两种实现方案

    vuex数据持久化的两种实现方案

    在vuex的时候刷新以后里面存储的state就会被浏览器释放掉,因为我们的state都是存储在内存中的,所以一刷新页面就会把state中的数据重置,这就涉及到vue数据持久化的问题,这篇文章主要给大家介绍了关于vuex数据持久化的两种实现方案,需要的朋友可以参考下
    2021-07-07
  • 详细讲解如何创建, 发布自己的 Vue UI 组件库

    详细讲解如何创建, 发布自己的 Vue UI 组件库

    当我们自己开发了一个 _UI Component_, 需要在多个项目中使用的时候呢? 我们首先想到的可能是直接复制一份过去对吗?我们为什么不发布一个 UI 组件库给自己用呢?下面小编和大家来一起学习下吧
    2019-05-05
  • rollup3.x+vue2打包组件的实现

    rollup3.x+vue2打包组件的实现

    本文主要介绍了rollup3.x+vue2打包组件的实现,详细的介绍了打包会存在的问题,包版本的问题,babel 转换jsx等问题,具有一定的参考价值,感兴趣的可以了解一下
    2023-03-03
  • Vue+EleMentUI实现el-table-colum表格select下拉框可编辑功能实例

    Vue+EleMentUI实现el-table-colum表格select下拉框可编辑功能实例

    这篇文章主要给大家介绍了关于Vue+EleMentUI实现el-table-colum表格select下拉框可编辑功能的相关资料,element-UI表格的使用相信大家都不陌生,文中给出了详细的代码示例,需要的朋友可以参考下
    2023-07-07
  • vue3项目中配置sass,vite报错Undefined mixin问题

    vue3项目中配置sass,vite报错Undefined mixin问题

    这篇文章主要介绍了vue3项目中配置sass,vite报错Undefined mixin问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • 详解Vue新增内置组件的使用

    详解Vue新增内置组件的使用

    这篇文章主要为大家介绍了Vue新增内置组件的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • 详解vuejs中执行npm run dev出现页面cannot GET/问题

    详解vuejs中执行npm run dev出现页面cannot GET/问题

    这篇文章主要介绍了详解vuejs中执行npm run dev出现页面cannot GET/问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04

最新评论