从0到1写vue源码(02手写diff算法)
snabbdom
snabbdom简介
搭建snabbdom环境
npm init
npm i -S snabbdom
搭建好后出现这样一个文件,sanabbdom里边就有js源码
接着安装webpack命令
npm install --save-dev webpack@5 webpack-cli@3 webpack-dev-server@3 --legacy-peer-deps
直接npm run dev命令
接着去官方网址 GitHub - snabbdom/snabbdom: A virtual DOM library with focus on simplicity, modularity, powerful features and performance.把 Example这个方法给放在src目录下的index.js文件中
至此搭建完成
snabbdom的h函数
什么是虚拟dom
虚拟dom
虚拟节点的属性
一般来说虚拟节点的属性有
{
children:undefined //是否有父子节点
data:{}, //元素样式属性及数据属性都会存在在这里
elm:undefined, //与真实dom的节点数
key:undefined, //唯一标识
sel:"div", //元素
text:"我是一个盒子" //文字
}
现在我编写了这样的函数,但是当我打印出来的数据是
h函数的使用
手写h函数
核心代码h.js
import vnode from './vnode.js' // 导入vnode模块,它可能是一个用于创建虚拟DOM节点的函数
// 定义一个简化版的h函数,用于创建虚拟DOM节点
// h函数可以接受三种类型的第三个参数c:字符串或数字、数组、或具有sel属性的对象
export default function(sel, data, c) {
// 检查是否传入了正确数量的参数(3个)
if (arguments.length !== 3) {
throw new Error("请传入正确的参数");
}
// 如果c是字符串或数字,表示这是文本内容
if (typeof c === "string" || typeof c === "number") {
// 调用vnode函数,传入选择器、数据、子节点(undefined,因为这里是文本内容)、文本内容和未定义的key
return vnode(sel, data, undefined, c, undefined);
}
// 如果c是数组,表示这是子节点列表
else if (Array.isArray(c)) {
let children = []; // 初始化子节点数组
for (let i = 0; i < c.length; i++) {
// 这里原本的逻辑有误,应该是检查c[i]的类型或属性,而不是c本身
// 修正为检查c[i]是否为对象且拥有sel属性,或者是否为vnode节点(这里假设vnode节点有sel属性)
if (!(typeof c[i] === "object" && c[i].hasOwnProperty("sel"))) {
throw new Error("请传入正确的参数,子节点应为对象且拥有sel属性或为vnode节点");
}
children.push(c[i]); // 将子节点添加到数组中
}
// 调用vnode函数,传入选择器、数据、子节点数组、未定义的文本内容和未定义的key
return vnode(sel, data, children, undefined, undefined);
}
// 如果c是对象且拥有sel属性,表示这是单个子节点(可能是另一个vnode)
else if (typeof c === "object" && c.hasOwnProperty("sel")) {
let children = [c]; // 将c作为唯一子节点放入数组
// 调用vnode函数,传入选择器、数据、子节点数组(包含c)、未定义的文本内容和未定义的key
return vnode(sel, data, children, undefined, undefined);
}
// 如果以上条件都不满足,则抛出错误
else {
throw new Error("请传入正确的参数");
}
}
vnode.js
// 这个函数就是把它换成对象的形式引进去
export default function vnode(sel, data, children, text, elm) {
console.log(sel, data, children, text, elm);
return { sel, data, children, text, elm };
}
// 源码是下边的那个
// export function vnode(sel, data, children, text, elm) {
// console.log(sel, data, children, text, elm);
// // const key = data === undefined ? undefined : data.key;
// return { sel, data, children, text, elm };
// }
index.js
import h from "./mysnabbdom/h"
let a = h("a", {}, [
h("a", {}, [h("a", {}, "999"),
h("a", {}, "999"),
]),
h("a", {}, "999"),
h("a", {}, "999"),
h("a", {}, "999")
])
console.log(a, "h");
snabbodm中diff算法
感受diff算法
了解diff算法机制(小修小补)
我们怎么验证是不是动态改变了这个li
首先我们改变了这个地方,然后点击按钮
他动态的改变了,但是没有更改我原来修改的属性,所以感受到了diff算法的魅力
但是这里是有个小bug的,如果我们在前面插入一个e
类似于这样的话,我们就会发现,e这个属性就会导致后边的属性改变,怎么避免这个问题呢?
我们要在{}里边加上一个key
类似于这样的感觉,是不是瞬间想到了vue和react中我们渲染的时候中绑定的key呢?
我们加上以后是这样的!!!!!!!!!!!!
所以总结成为一句话
了解diff算法(暴力拆卸)
如果我们是数据不变我们绑定的key也没有问题,出来的情况是
直接由ul转化为ol,那么他所有的li的diff对比,就会重新执行,相当于墙砸了,重新垒墙!这样的情况不是同一个虚拟节点
还有一种情况就是我们虚拟diff啊,他是要同级比较的,比如
<div>
<span>
<li></li>
<li></li>
</span>
</div>
<div>
<span>
<li></li>
<li></li>
</span>
</div>
//这2个就不会比较,因为他们位于的层级不同,他们会比较的只有<div></div>会进行比较
//而li是不会比较的
diff算法的核心实现逻辑导图
手写diff算法
手写第一次上树
原文地址:https://blog.csdn.net/xyfwang/article/details/140341732
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!