人在上海,因为疫情,没有办法拿到这本书,本书没有电子版,那就看代码仓库吧。
书的介绍
本书基于Vue.js 3,从规范出发,以源码为基础,并结合大量直观的配图,循序渐进地讲解Vue.js中各个功能模块的实现,细致剖析框架设计原理。全书共18章,分为六篇,主要内容包括:框架设计概览、响应系统、渲染器、组件化、编译器和服务端渲染等。通过阅读本书,对Vue.js 2/3具有上手经验的开发人员能够进一步理解Vue.js框架的实现细节,没有Vue.js使用经验但对框架设计感兴趣的前端开发人员,能够快速掌握Vue.js的设计原理。
course1-权衡的艺术
我对源码进行了注释和修改
这部分代码主要是写了一个render函数,递归的将一个固定对象结构渲染到DOM中
固定对象结构形如
interface node {
tag: string,
children: string | node[]
}
<body></body>
<script type="module">
import { Render, obj } from "./render.js";
// 渲染到 body 下
Render(obj, document.body);
</script>
export async function Render(obj, root) {
// 创建DOM标签
const el = document.createElement(obj.tag)
if (typeof obj.children === 'string' /* 如果children类型是string */ ) {
const text = document.createTextNode(obj.children)
el.appendChild(text)
} else if (Array.isArray(obj.children)) /* 如果children的类型是Array */ {
// array,递归调用 Render,使用 el 作为 root 参数
for (let child of obj.children) {
Render(child, el)
}
}
// 将元素添加到 root
root.appendChild(el)
}
export const obj = {
tag: "div",
children: [{
tag: "span",
children: "hello world",
},
{
tag: "div",
children: [{
tag: "span",
children: "this ",
},
{
tag: "span",
children: "is ",
},
{
tag: "span",
children: "render",
},
],
},
],
};
course2-框架设计的核心要素
这一部分应该是在介绍框架使用的打包工具配置和演示吧。
没什么可说的。
没了
course3-Vue3 的设计思路
这一部分主要演示vnode绑定事件
此时固定对象结构有了名字,那就是vnode
interface vnode {
tag: string,
props: {
onClick: () => void
},
children: string | vnode[]
}
code1.html
到code3.html
,从开始的vnode
对象,到后来的组件对象
<body></body>
<script type="module">
import { renderer } from "./code3.js";
const MyComponent = {
// render函数
render() {
return {
tag: "div",
props: {},
children: [
{
tag: "span",
props: {
onClick: () => alert("hello"),
},
children: "click me",
},
{
tag: "div",
props: {},
children: "this is span",
},
],
};
},
};
// vnode
const vnode = {
tag: MyComponent,
};
renderer(vnode /* vnode */, document.body /* 挂载容器 */);
</script>
export function renderer(vnode /* vnode */ , container /* 挂载容器 */ ) {
if (typeof vnode.tag === 'string') {
// 说明 vnode 描述的是标签元素
mountElement(vnode, container)
} else if (typeof vnode.tag === 'object') {
// 说明 vnode 描述的是组件
mountComponent(vnode, container)
}
}
function mountElement(vnode, container) {
// 使用 vnode.tag 作为标签名称创建 DOM 元素
const el = document.createElement(vnode.tag)
// 遍历 vnode.props 将属性、事件添加到 DOM 元素
for (const key in vnode.props) {
if (/^on/.test(key)) {
// 如果 key 以 on 开头,那么说明它是事件
el.addEventListener(
key.substr(2).toLowerCase(), // 事件名称 onClick ---> click
vnode.props[key] // 事件处理函数
)
}
}
// 处理 children
if (typeof vnode.children === 'string') {
// 如果 children 是字符串,说明是元素的文本子节点
el.appendChild(document.createTextNode(vnode.children))
} else if (Array.isArray(vnode.children)) {
// 递归地调用 renderer 函数渲染子节点,使用当前元素 el 作为挂载点
vnode.children.forEach(child => renderer(child, el))
}
// 将元素添加到挂载点下
container.appendChild(el)
}
function mountComponent(vnode, container) {
// 调用组件函数,获取组件要渲染的内容(虚拟 DOM)
const subtree = vnode.tag.render()
// 递归调用 renderer 渲染 subtree
renderer(subtree, container)
}
没了