《vuejs设计和实现》笔记
第一篇:框架设计概览
权衡
- 命令式:关注过程,eg:jQuery
- 声明式:关注结果
- 运行时:手写 render 函数的树形结构数据对象
- 运行时编译:把html字符编译成树形结构数据对象,再调用render渲染,eg:Vue。优点在于可以分析用户提供的内容。
- 编译时:把 html 直接编译成命令式代码,eg:Svelte。灵活性不足。
核心要素
- 开发体验:
- 友好的警告信息
warn()
- 直观的输出内容
initCustomFormatter()
,可以通过修改浏览器 devtool 设置让输出更友好
- 友好的警告信息
- 框架体积:
- 仅开发环境提供警告:
__DEV__
结合 Rollupjs 插件配置 /*#__PURE__*/foo()
告诉 rollupjs,foo()的调用不会产生副作用,可进行 tree shaking
- 仅开发环境提供警告:
- 构建产物:为不同的环境输出不同的包
<script>
IIFE立即执行函数<script type='module'>
ESM- vue.runtime.esm-bundler.js
- vue.esm-browser.js
- 特性开关:利用 rollup 预定义常量插件来实现,
__VUE_OPTIONS_API__
- 错误处理:为用户提供统一的错误处理接口:
registerErrorHandler()
callWithErrorHandling()
- TS类型支持
设计思路
- 声明式地描述 UI(使用模板或手写渲染函数使用虚拟DOM来描述 UI)
- 虚拟 DOM:用 js 对象来描述真实的 DOM 结构
- 渲染器:把虚拟 DOM 创建成真实的 DOM。
h()
函数:用于创建 vnodes,返回对象,辅助虚拟DOM创建render()
渲染函数,创建虚拟 DOM 树renderer()
渲染器函数:创建元素、添加属性和事件、处理 children……
- 组件:是一组DOM元素的封装,可用函数/对象代表组件,返回要渲染的内容 p58
- renderer 函数增加对组件的支持,当tag为组件(函数/对象)时……
- 编译器:将模板
<template>
编译成渲染函数render()
,并添加到<script>
组件对象上。 运行时渲染器调用渲染函数,遍历返回的虚拟 DOM 树,并基于它创建实际的 DOM 节点。
第二篇:响应系统
情景
- 有一个数据对象
obj
和若干个依赖该数据对象的副作用函数effect(){...obj...}
- 希望数据对象发生变化的时候,副作用函数自动重新执行一遍
思路
- proxy代理,(调用副作用函数时)
get
存储副作用函数track()
,(修改数据对象时)set
重新执行副作用函数trigger()
- 存储副作用函数到桶里
bucket
——怎么存?用什么数据结构存储?bucket = weakmap map set
- 如果副作用函数为匿名,怎么存储?——手动注册,保存到全局变量
- 修改对象中的一个属性时怎么不触发没读取该属性的副作用函数?(此时用 set 作为桶的数据结构)——修改桶的数据结构,让每个属性对应其副作用函数。
- weakmap 不影响垃圾回收,优化内存
- 分支切换时,不会删掉切换前属性存下来的遗留副作用函数,怎么办?——p78 分支副作用函数执行时先移出,执行完再重新移入,确保保存的副作用函数是和当前分支属性关联的。
- 要移出得先收集副作用函数的所有关联依赖集合——收集副作用函数时,新增 deps 属性保存依赖
cleanup()
移除依赖
- 避免无限循环,新建数据
effectsToRun
代码实现
html 部分
<h1 id="text1">Hello</h1>
<button id="btn">click to change obj</button>
主要流程
const data = { key1: "value1", key2: "value2" }; //响应式源对象
const bucket = new WeakMap(); //存储副作用函数的桶
let activeEffect; //用一个全局变量存储被注册的副作用函数
//代理 data
const obj = new Proxy(data, {
//拦截读取属性
get(target, key) {
track(target, key); //将副作用函数添加到存储副作用函数的桶中
return target[key]; //继续读取属性值
},
//拦截修改属性
set(target, key, value) {
target[key] = value; //继续修改属性
trigger(target, key); //把副作用函数从桶里取出并执行
},
});
//副作用函数
effect(() => {
setTimeout(() => {
console.log("正在执行副作用函数");
const text1 = document.getElementById("text1");
text1.textContent = obj.key1; //用到了外部数据对象
}, 1000);
});
//修改obj,看是否副作用函数是否再次执行
setTimeout(() => {
let btn = document.getElementById("btn");
btn.addEventListener("click", () => {
obj.key1 = "World"; //修改 obj
console.log("修改了obj");
});
}, 1000);
函数封装
//注册副作用函数
function effect(fn) {
//设置当前副作用函数
function effectFn() {
cleanup(effectFn); //调用 cleanup 函数完成清除工作
activeEffect = effectFn; //将effectFn设置为当前副作用函数
fn(); //执行副作用函数
}
effectFn.deps = []; //用来存储所有与该副作用函数相关联的依赖集合
effectFn();
}
//在每次副作用函数执行时,将副作用函数从依赖集合中移除
function cleanup(effectFn) {
for (let i = 0; i < effectFn.deps.length; i ) {
const deps = effectFn.deps[i];
deps.delete(effectFn);
}
effectFn.deps.length = 0;
}
//把副作用函数存储到桶里
function track(target, key) {
//如果当前没有副作用函数就算了
if (!activeEffect) return;
//如果当前有副作用函数,则存储到桶的weakmap>map>set里
let depsMap = bucket.get(target);
if (!depsMap) {
bucket.set(target, (depsMap = new Map())); //初始化map
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, (deps = new Set())); //初始化set
}
deps.add(activeEffect); //将当前激活的副作用函数添加到桶里
//deps 就是一个与当前副作用函数存在联系的依赖集合
//将其添加到 activeEffect.deps 数组中
activeEffect.deps.push(deps);
}
//把副作用函数从桶里取出并执行
function trigger(target, key) {
const depsMap = bucket.get(target);
//如果桶里没有副作用函数就算了
if (!depsMap) return;
//如果桶里有副作用函数,则都取出来执行
const effects = depsMap.get(key);
//为了避免无限循环,执行时需要额外操作
// effects && effects.forEach((fn) => fn());
const effectsToRun = new Set(effects);
effectsToRun.forEach((effectFn) => effectFn());
}
reactive proxy 只能代理对象
非原始值(引用数据类型)响应方案
原始值(基本数据类型)响应方案
第三篇:渲染器
设计
挂载与更新
(简单、双端、快速)Diff算法
第四篇:组件化
实现原理
异步组件
函数式组件
内建组件和模块
第五篇:编译器
编译器核心技术
解析器
编译优化
第六篇:服务端渲染
同构渲染
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbagec
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01