从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算法

  手写第一次上树

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值