diff 算法

发布于:2024-10-15 ⋅ 阅读:(131) ⋅ 点赞:(0)

1 功能

提升性能,通过使用虚拟dom【虚拟dom其实就是数据(把dom数据化)】

2 主流:snabbdom、virtual-dom

snabbdom - npm

snabbdom/README-zh_CN.md at b301a9220918254aa9c79ad91012780ff8c55862 · snabbdom/snabbdom · GitHub

virtual-dom - npm

3 搭建环境

npm init -y

npm install webpack@5 webpack-cli@3 webpack-dev-server@3 -S

npm install snabbdom -S

3.1 修改package.json运行命令

【"dev": "webpack-dev-server --open"】

{
  "name": "diff",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "snabbdom": "^3.6.2",
    "webpack": "^5.95.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.3"
  }
}

3.2 新建配置webpack.config.js

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: __dirname + '/public',
        filename: './js/[name].js'
    },
    devServer: {
        contentBase: './public',
        inline: true
    }
}

3.3 新建入口文件和出口文件

html:public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>11111111111</h1>
    <script type="text/javascript" src="/js/index.js"></script>
</body>
</html>

js:src/index.js

alert(123)

3.4 检查运行环境

npm run dev

4 使用snabbdom示例

4.1 找到示例覆盖index.js

import {
  init,
  classModule,
  propsModule,
  styleModule,
  eventListenersModule,
  h
} from "snabbdom";

const patch = init([
  // 通过传入模块初始化 patch 函数
  classModule, // 开启 classes 功能
  propsModule, // 支持传入 props
  styleModule, // 支持内联样式同时支持动画
  eventListenersModule // 添加事件监听
]);

const container = document.getElementById("container");

const vnode = h("div#container.two.classes", { on: { click: someFn } }, [
  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(container, vnode);

const newVnode = h(
  "div#container.two.classes",
  { on: { click: anotherEventHandler } },
  [
    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!")
  ]
);
// 再次调用 `patch`
patch(vnode, newVnode); // 将旧节点更新为新节点

4.2 示例报错

  • Uncaught ReferenceError: someFn is not defined

// 将 someFn 替换成 function(){}  
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!")
]);
  • Uncaught TypeError: Cannot read properties of null (reading 'nodeType') 

<body>
    // 在 public/index.html 中增加 id 为 container 的元素
    <div id="container"></div>

    <script type="text/javascript" src="/js/index.js"></script>
</body>
  •  Uncaught ReferenceError: anotherEventHandler is not defined

const newVnode = h(
  "div#container.two.classes",
  // 将 anotherEventHandler 替换成 function(){}
  { 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!")
  ]
);

4.3 成功

5 虚拟节点 和 真实节点

  • 虚拟节点
{
    children: undefined
    data:{}
    elm: undefined
    key: undefined
    sel: "h2"
    text: "你好"
}
  • 真实节点
<h1>你好</h1>

6 新老节点替换规则

1、如果新老节点不是同一个节点名称,那么就暴力删除旧的节点,创建插入新的节点。

2、只能同级比较,不能跨层比较。如果跨层那么就暴力删除旧的节点,创建插入新的节点。

3、注意!!!   如果要提升性能,一定要加入key,key是唯一标识,在更改前后,判断是不是同一个节点。


网站公告

今日签到

点亮在社区的每一天
去签到