Vuejs设计与实现7-组件实现原理
创始人
2024-05-04 00:06:36
0

九、组件实现原理

渲染组件

一个组件内部必须要使用 render 进行渲染,且返回虚拟 DOM

这是一个最简组件实例

const MyComponent = {// 组件名称,可选name: "MyComponent",// 组件的渲染函数,其返回值必须为虚拟 DOMrender() {// 返回虚拟 DOMreturn {type: "div",children: `我是文本内容`,};},
};

渲染器中的 mountComponent 函数完成组件的渲染

function mountComponent(vnode, container, anchor) {// 通过 vnode 获取组件的选项对象,即 vnode.typeconst componentOptions = vnode.type;// 获取组件的渲染函数 renderconst { render } = componentOptions;// 执行渲染函数,获取组件要渲染的内容,即 render 函数返回的虚拟const subTree = render();// 最后调用 patch 函数来挂载组件所描述的内容,即 subTreepatch(null, subTree, container, anchor);
}

组件更新

组件初始化步骤:

  1. 取得 data 函数后用 reactive 将其变成响应式的
  2. render 函数内将 this 指向 state,并将 state 作为第一个参数传入 render 函数

将渲染任务包装到一个副作用函数 effect 里面,即可实现响应式更新数据

若要使每次响应式数据修改后,effect 仅执行一次,则需要引入调度器概念
这是书中给出的最简调度器实例

即先把 effect 放入微任务队列,等执行栈清空再调出来执行

// 任务缓存队列,set可以自动去重
const queue = new Set();
// 一个标志,代表是否正在刷新任务队列
let isFlushing = false;
// 创建一个立即 resolve 的 Promise 实例
const p = Promise.resolve();
// 调度器的主要函数,用来将一个任务添加到缓冲队列中,并开始刷新队列
function queueJob(job) {// 将 job 添加到任务队列 queue 中queue.add(job);// 如果还没有开始刷新队列,则刷新之if (!isFlushing) {// 将该标志设置为 true 以避免重复刷新isFlushing = true;// 在微任务中刷新缓冲队列p.then(() => {try {// 执行任务队列中的任务queue.forEach((job) => job());} finally {// 重置状态isFlushing = false;queue.clear = 0;}});}
}

父子组件

这是一个简单的父子组件代码

// 子组件
// 父组件
const vnode = {type: MyComponent,props: {title: 'A Big Title'}
}

父组件更新导致子组件更新(被动更新)过程:

  1. 父组件自更新
  2. 渲染器检查 subTree 发现存在 vnode,则调用 patchComponent 实现子组件更新

setup 函数

setup 函数为配合组合式 API 所引入的

他有如下两种返回值形式

// 返回函数
const comp = {setup() {return () => {return {type: "div",children: "give up for vuejs",};};},
};// 返回对象
const comp = {setup() {const count = ref(0);return {count,};},render() {return {type: "div",children: `count is ${this.count}`,};},
};

setup 接收两个参数,分别是 props 以及 setupContext

setupContext 包含以下四个主要对象

  1. slots 插槽
  2. emit 自定义事件
  3. attrs 自定义属性
  4. expose 暴露

emit 实现

只需要实现一个 emit 函数并将其添加到 setupContext 对象中


相关内容

热门资讯

中证A500ETF摩根(560... 8月22日,截止午间收盘,中证A500ETF摩根(560530)涨1.19%,报1.106元,成交额...
A500ETF易方达(1593... 8月22日,截止午间收盘,A500ETF易方达(159361)涨1.28%,报1.104元,成交额1...
何小鹏斥资约2.5亿港元增持小... 每经记者|孙磊    每经编辑|裴健如 8月21日晚间,小鹏汽车发布公告称,公司联...
中证500ETF基金(1593... 8月22日,截止午间收盘,中证500ETF基金(159337)涨0.94%,报1.509元,成交额2...
中证A500ETF华安(159... 8月22日,截止午间收盘,中证A500ETF华安(159359)涨1.15%,报1.139元,成交额...
科创AIETF(588790)... 8月22日,截止午间收盘,科创AIETF(588790)涨4.83%,报0.760元,成交额6.98...
创业板50ETF嘉实(1593... 8月22日,截止午间收盘,创业板50ETF嘉实(159373)涨2.61%,报1.296元,成交额1...
港股异动丨航空股大幅走低 中国... 港股航空股大幅下跌,其中,中国国航跌近7%表现最弱,中国东方航空跌近5%,中国南方航空跌超3%,美兰...
电网设备ETF(159326)... 8月22日,截止午间收盘,电网设备ETF(159326)跌0.25%,报1.198元,成交额409....
红利ETF国企(530880)... 8月22日,截止午间收盘,红利ETF国企(530880)跌0.67%,报1.034元,成交额29.0...