手摸手vue中虚拟dom函数和diff算法

r囧r小猫 2023-01-08 02:12 236阅读 0赞

snabbdom简介和测试环境搭建

  1. npm i-S snabbdom
  2. npm i -D webpack@5 webpack-cli@3 webpack-dev-server@3

  3. 修改package.json中”script”属性的“dev”:“webpack-dev-server”

  4. 配置webpack.config.js 文件

    // 从https://www.webpackjs.com/官网照着配置
    const path = require(‘path’);

    module.exports = {

    1. // 入口
    2. entry: './src/index.js',
    3. // 出口
    4. output: {
    5. // 虚拟打包路径,就是说文件夹不会真正生成,而是在8080端口虚拟生成
    6. publicPath: 'xuni',
    7. // 打包出来的文件名,不会真正的物理生成
    8. filename: 'bundle.js'
    9. },
    10. devServer: {
    11. // 端口号
    12. port: 8080,
    13. // 静态资源文件夹
    14. contentBase: 'www'
    15. }

    };

  5. 打包测试

虚拟DOM和h函数

diff是发生在虚拟的DOM层,算出应该如何让最小量更新,最后反映到真正的DOM

h函数用来产生虚拟节点(vnode),可以嵌套使用,从而得到虚拟DOM树

  1. import vnode from './vnode.js';
  2. // 编写一个低配版本的h函数,这个函数必须接受3个参数,缺一不可
  3. // 相当于它的重载功能较弱。
  4. // 也就是说,调用的时候形态必须是下面的三种之一:
  5. // 形态① h('div', {}, '文字')
  6. // 形态② h('div', {}, [])
  7. // 形态③ h('div', {}, h())
  8. export default function (sel, data, c) {
  9. if (arguments.length != 3)
  10. throw new Error('对不起,h函数必须传入3个参数,我们是低配版h函数');
  11. if (typeof c == 'string' || typeof c == 'number'){
  12. return vnode(sel,data,undefined,c,undefined)
  13. }else if(Array.isArray(c)){
  14. let children = []
  15. for (var i =0 ;i < c.length;i++){
  16. if(!(typeof c[i] == 'object' && c[i].hasOwnProperty('sel')))
  17. throw new Error('传入的数组参数中有项不是h函数');
  18. children.push(c[i])
  19. }
  20. return vnode(sel,data,children,undefined,undefined)
  21. }else if(typeof c == 'object' && c.hasOwnProperty('sel')){
  22. let children = [c]
  23. return vnode(sel,data,children,undefined,undefined)
  24. }else{
  25. throw new Error('传入的数组参数中有项不是h函数');
  26. }
  27. };

虚拟节点的属性

  1. sel
  2. data
  3. children
  4. text
  5. elm
  6. key

diff算法

我们要手写h函数(用于产生虚拟节点),vnode函数(节点转化成对象),patch函数(用于上树,判断新旧是否是同个节点),

diff处理新旧节点是否是同个节点

  1. 只有同一个虚拟节点,才能进行精细化比较

    选择器相同且key相同

  2. 只进行同层比较,不会进行跨层比较

在这里插入图片描述

新旧节点不是同一个节点

创建新节点的时候,所有的子节点需要递归创建。createElements函数(用于创建节点,将vnode创建为DOM,是孤儿节点,上树还需要patch函数,不进行插入)

手写递归创建节点,注意递归主要利用返回值的dom对象,因为标杆在新节点的父子节点比较麻烦
在这里插入图片描述

appendChild与insertBefore之前的差别

  1. appendChild() 方法:可以向节点的子节点列表的末尾添加新的子节点。
    比如:appendChild(newchild)括号里可以是创建的标签var newchild = document.createElement
  2. insertBefore() 方法:
    可在已有的字节点前中插入一个新的子节点。比如:insertBefore(newchild,rechild)
    参数:
    (newchild: 要插入的新节点。
    rechild: 指定此节点前插入节点
  3. 相同之处:插入子节点。
  4. 不同之处
    appendChild是在父节点中的字节点的末尾添加新的节点(相对于父节点来说)。
    insertBefore是在已有的节点前添加新的节点(相对于子节点来说的)

对于新旧节点都有children属性的情况下采用精细化比较

在这里插入图片描述

四种命中方法(自上往下,命中一种就不会往下继续判断了)

  1. 新前与旧后
  2. 新后与旧后
  3. 新后与旧前
  4. 新前与旧后
  5. 循环遍历,移动到oldstartidx之前

新增

如果是旧节点先循环完毕,如果新节点中还有剩余节点,说明他们是要新增的节点。
新前>=新后菜可以新增
在这里插入图片描述
在这里插入图片描述

删除

多删除
如果是新节点先循环完毕,如果老节点中还有剩余节点,说明他们是要被删除的节点。
旧前>=旧后菜可以删除
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

复杂

当第三种情况命中的时候,移动新前指向老节点的旧后的后面
在这里插入图片描述

当第四种情况命中的时候,注意呀移动节点,移动新前指向老节点的旧前的前面
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUxMTIzNg_size_16_color_FFFFFF_t_70 9

在这里插入图片描述

参考:
解析vue2.0的diff算法

发表评论

表情:
评论列表 (有 0 条评论,236人围观)

还没有评论,来说两句吧...

相关阅读