文章目录
来自尚硅谷的课程笔记 课程链接 尚硅谷邵山欢(考拉老师)Vue之虚拟DOM和diff算法
加入大量的注释以及大量改写,新增很多插图解释diff算法
第八章仔细说明了老师说的一些比较含糊的地方
源码链接 https://gitee.com/ykang2020/vue_learn
0. 文章结构预览
0.1 虚拟DOM如何被渲染函数(h函数)产生
目标:手写h函数
0.2 diff算法的原理
目标:手写diff算法
0.3 虚拟DOM如何通过diff变成真正的DOM
1. 介绍
1.1 diff算法
精细化比较
1.2 虚拟DOM
本课程不涉及DOM如何变成虚拟DOM
这属于模板编译原理范畴
但是虚拟节点变成DOM节点在diff中可以做到
1.3 关系——diff是发生在虚拟DOM上的
新虚拟DOM和旧虚拟DOM进行diff(精细化比较),算出应该如何最小量更新,最后反映到真正的DOM上
2. snabbdom 简介 及 准备工作
2.1 简介
snabbdom
(瑞典语,“速度”)是著名的虚拟DOM库,是diff算法的鼻祖
Vue源码借鉴了snabbdom
源码使用TypeScript写的https://github.com/snabbdom/snabbdom
从npm下载的是build出来的JavaScript版本
npm install -D snabbdom
2.2 搭建初始环境
1. 安装snabbdom
cnpm install -S snabbdom
2. 安装webpack5并配置
cnpm i -D webpack@5 webpack-cli@3 webpack-dev-server@3
配置webpack5
module.exports = {
// webpack5 不用配置mode
// 入口
entry: "./src/index.js",
// 出口
output: {
// 虚拟打包路径,文件夹不会真正生成,而是在8080端口虚拟生成
publicPath: "xuni",
// 打包出来的文件名
filename: "bundle.js",
},
// 配置webpack-dev-server
devServer: {
// 静态根目录
contentBase: 'www',
// 端口号
port: 8080,
},
};
3. 复制官方demo Example
src/index.js
import {
init,
classModule,
propsModule,
styleModule,
eventListenersModule,
h,
} from "snabbdom";
const patch = init([
// Init patch function with chosen modules
classModule, // makes it easy to toggle classes
propsModule, // for setting properties on DOM elements
styleModule, // handles styling on elements with support for animations
eventListenersModule, // attaches event listeners
]);
const container = document.getElementById("container");
const vnode = h("div#container.two.classes", {
on: {
click: function () {
} } }, [
h("span", {
style: {
fontWeight: "bold" } }, "This is bold"),
" and this is just normal text",
h("a", {
props: {
href: "/foo" } }, "I'll take you places!"),
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);
const newVnode = h(
"div#container.two.classes",
{
on: {
click: function () {
} } },
[
h(
"span",
{
style: {
fontWeight: "normal", fontStyle: "italic" } },
"This is now italic type"
),
" and this is still just normal text",
h("a", {
props: {
href: "/bar" } }, "I'll take you places!"),
]
);
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
3. h函数的介绍与使用
3.1 介绍
用来产生虚拟节点(vnode)
虚拟节点vnode的属性
{
children: undefined// 子元素 数组
data: {
} // 属性、样式、key
elm: undefined // 对应的真正的dom节点(对象),undefined表示节点还没有上dom树
key: // 唯一标识
sel: "" // 选择器
text: "" // 文本内容
}
3.2 使用h函数 创建虚拟节点
// 创建虚拟节点
var myVnode1 = h('a', {
props: {
href: 'https://www.baidu.com' } }, 'YK菌')
console.log(myVnode1)
3.3 使用patch函数 将虚拟节点上DOM树
// 创建patch函数
const patch = init([
classModule,
propsModule,
styleModule,
eventListenersModule,
]);
// 创建虚拟节点
var myVnode1 = h(
"a",
{
props: {
href: "https://www.baidu.com", target: "_blank" } },
"YK菌"
);
// 让虚拟节点上树
let container = document.getElementById("container");
patch(container, myVnode1);
3.4 h函数嵌套使用,得到虚拟DOM树(重要)
const myVnode3 = h('ul', [
h('li', '苹果'),
h('li', '香蕉'),
h('li', '西瓜'),
h('li', '番茄'),
])
// 让虚拟节点上树
let container = document.getElementById("container");
patch(container, myVnode3);
const myVnode3 = h('ul', [
h('li', '苹果'),
h('li', [
h('div', [
h('p', '香蕉'),
h('p', '草莓')
])
]),
h('li', h('span','西瓜')),
h('li', '番茄'),
])
4. 手写h函数
vnode.js
将传入的参数组合成对象返回
/**
* 产生虚拟节点
* 将传入的参数组合成对象返回
* @param