人在上海,因为疫情,没有办法拿到这本书,本书没有电子版,那就看代码仓库吧。
书的介绍
本书基于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)}}// 将元素添加到 rootroot.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",},],};},};// vnodeconst 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 ---> clickvnode.props[key] // 事件处理函数)}}// 处理 childrenif (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 渲染 subtreerenderer(subtree, container)}
没了
