Vue渲染器之组件的渲染

对于一个a.vue文件(组件),它有template,script,style三部分,使用的时候需要先import a from ./a.vue

经过vue-loader处理后 , a 其实变成了一个对象,template就变成了对象中的render函数,返回的是VNode.其中vnode.type 属性来存储组件的选项对象a

js 复制代码
//这个组件对应的VNode
{
type:a,
//props:{}
//....
}

现在处理组件转变为处理这个对象,现在只需要聚焦这个对象即可了

在render中的 patch 函数中会根据 type 判断节点类型,其实处理组件跟处理普通标签差不多,当n1为null时,执行 mountComponent ,反之执行 updateComponent

组件模版与状态

现在再来讨论一下,这个组件对象里应该包含什么东西,首先对于一个组件,我们要知道它渲染了什么,这里用虚拟DOM表示。Vue规定组件内的render函数的返回值就是虚拟DOM,所以我们现在可以得到组件的描述-虚拟DOM(之后用subTree代指)

接着组件应该有自己的状态也就是数据,规定是data函数返回的,并且这些数据可以在render函数中通过this访问。

进行组件维护

对于组件我们必须注册一个实例,用来维护组件运行过程中的所有信息,例如生命周期函数、组件渲染的子树(subTree)、组件是否已经被挂载、组件自身的状态等

应该在第一次渲染也就是mountComponent注册它的实例。

js 复制代码
function mountComponent(vnode, container, anchor) {
  const { render, state } = vnode.type
  const state = reactive(data())
  const instance = {
    // 组件自身的状态数据,即 data
    state,
    // 一个布尔值,用来表示组件是否已经被挂载,初始值为 false
    isMounted: false,
    // 组件所渲染的内容,即子树(subTree)
    subTree: null
  }

  // 将组件实例设置到 vnode 上,用于后续更新
  vnode.component = instance
}

结合响应式

接着执行setupRenderEffect,它的作用就是注册带副作用的渲染函数.用来完成子组件的自动更新.而这个副作用函数componentUpdateFn做了什么呢

其实很简单就是利用之前的实例拿到上面的属性isMounted进行判断

如果是false,渲染组件,执行renderComponentRoot可以拿到subTress,之后在执行patch进行挂载.

反正更新,首先执行updateComponentPreRender更新组件实例,再执行patch

父组件导致的更新

上面是子组件自身状态改变自动更新,下面来讨论一下父组件的状态改变导致子组件更新

也就是会触发上面提到的updateComponent,在里面会比较组件VNode中的props,chilren等属性是否相同,相同代表不需要更新,反正需要更新.接下来会进行下面两步操作

  1. invalidateJob(instance.update)
  2. instance.update()

第一步是因为Vue更新粒度是组件级别的,子组件也可能因为自身数据改变触发更新,这样可以避免重复渲染

第二步是触发了子组件的更新渲染

深入探析如何注册组件实例(处理setup)

在这个createComponentInstance函数中会进行组件实例的创建,创建之后我们还要设置实例才行,如果是组合式api的写法交给这个函数setupComponent进行设置的.

在这个函数中先初始化props,slots.接着执行核心函数setupStatefulComponent,它的作用是

  1. 创建渲染上下文代理,虽然实例中会存放对应的属性,例如data,setupState(setup的返回值),props,ctx(选项式api中的methods,computer,inject等),但是为了方便用户,render函数会直接访问实例instance.ctx属性,所以需要对它加一层代理,用来控制数据的读取及修改.看看他的捕获函数
  • get: 访问的key不以 <math xmlns="http://www.w3.org/1998/Math/MathML"> 开头 , 依次判断 s e t u p S t a t e , d a t a , p r o p s , c t x 是否包含这个 k e y . 反正 , 进行判断是不是 V u e 暴露出的 开头,依次判断setupState,data,props,ctx是否包含这个key.反正,进行判断是不是Vue暴露出的 </math>开头,依次判断setupState,data,props,ctx是否包含这个key.反正,进行判断是不是Vue暴露出的xxx属性或方法,再判断是不是在ctx中以$开头的key,最后判断他是不是全局属性
  • set: 开发环境修改props会提示
  1. 处理setup函数
  • 首先会创建setupContext对象,他就是setup函数的第二个参数,可以解构出attrs、slots和 emit三个属性以及expose函数。setupContext的目的就是让我们可以在setup函数内部访问组件实例上的属性、插槽、派发事件的方法enit以及暴露组件方法的函数expose.
  • 执行setup,第一个参数是instance.props,第二个参数是setupContext.返回结果可以是一个对象也可以是一个函数,当返回函数时将被当成render函数.如果setupResult是一个对象,那么对其返回结果做一层代理,把结果赋值给instance.setupState,
相关推荐
小阮的学习笔记6 分钟前
Vue3中使用LogicFlow实现简单流程图
javascript·vue.js·流程图
YBN娜7 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=7 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
杨荧9 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
minDuck11 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!32 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。37 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼43 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端