虚拟dom,diff算法,插槽,数组去重,数组排序整理

  1. 什么是虚拟dom

    用js来描述元素与元素之间的关系 [父子 兄弟]

    目的:高效渲染 以及快速更新

    高效渲染和快速更新的手段是diff算法

  2. diff算法

    • Diff算法就是在虚拟DOM树从上至下进行同层比对,如果上层已经不同了,那么下面的DOM全部重新渲染。这样的好处是算法简单,减少比对次数,加快算法完成速度。

diff 算法是⼀种通过同层的树节点进⾏⽐较的⾼效算法

其有两个特点:

  • ⽐较只会在同层级进⾏, 不会跨层级⽐较
  • 在diff⽐较的过程中,循环从两边向中间⽐较

diff 算法在很多场景下都有应⽤,在 vue 中,作⽤于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点 ⽐较

⼆、⽐较⽅式 diff 整体策略为:深度优先,同层⽐较

1. ⽐较只会在同层级进⾏, 不会跨层级比较

虚拟dom,diff算法,插槽,数组去重,数组排序整理

2. ⽐较的过程中,循环从两边向中间收拢

虚拟dom,diff算法,插槽,数组去重,数组排序整理 

 

 下⾯举个 vue 通过 diff 算法更新的例⼦:

新旧 VNode 节点如下图所示

虚拟dom,diff算法,插槽,数组去重,数组排序整理

 第⼀次循环后,发现旧节点D与新节点D相同,直接复⽤旧节点D作为 diff 后的第⼀个真实节点,同时 旧节点 endIndex 移动到C,新节点的 startIndex 移动到了c

虚拟dom,diff算法,插槽,数组去重,数组排序整理

 第⼆次循环后,同样是旧节点的末尾和新节点的开头(都是 C)相同,同理, diff 后创建了 C 的真实节点 插⼊到第⼀次创建的 B 节点后⾯。同时旧节点的 endIndex 移动到了 B,新节点的 startIndex 移动 到了E

虚拟dom,diff算法,插槽,数组去重,数组排序整理

第三次循环中,发现E没有找到,这时候只能直接创建新的真实节点 E,插⼊到第⼆次创建的 C 节点之 后。同时新节点的 startIndex 移动到了 A。旧节点的 startIndex 和 endIndex 都保持不动 

虚拟dom,diff算法,插槽,数组去重,数组排序整理 

第四次循环中,发现了新旧节点的开头(都是 A)相同,于是 diff 后创建了 A 的真实节点,插⼊到前⼀ 次创建的 E 节点后⾯。同时旧节点的 startIndex 移动到了 B,新节点的 startIndex 移动到了 B

虚拟dom,diff算法,插槽,数组去重,数组排序整理 

第五次循环中,情形同第四次循环⼀样,因此 diff 后创建了 B 真实节点 插⼊到前⼀次创建的 A 节点 后⾯。同时旧节点的 startIndex 移动到了 C,新节点的 startIndex 移动到了 F 

虚拟dom,diff算法,插槽,数组去重,数组排序整理

新节点的 startIndex 已经⼤于 endIndex 了,需要创建 newStartIdx 和 newEndIdx 之间的所有 节点,也就是节点F,直接创建 F 节点对应的真实节点放到 B 节点后⾯

虚拟dom,diff算法,插槽,数组去重,数组排序整理 

 三、原理分析 当数据发⽣改变时, set ⽅法会调⽤ Dep.notify 通知所有订阅者 Watcher ,订阅者就会调⽤ patch 给真实的 DOM 打补丁,更新相应的视图

插槽

  • 什么是插槽

    (在子组件中用<slot></slot>划出一块区域来显示父组件中的页面结构,显示的结构在父组件的子组件标签中设置就行)

  • 插槽怎么显示数据

    显示的结构在父组件的子组件标签中设置就行

  • 插槽分为几种

    默认插槽 具名插槽 作用域插槽

  • 作用域插槽怎么用

    • 在子组件<slot></slot>通过v-bind绑定一个属性,挂载变量

    • <slot name="content" v-bind:us="user"></slot>

      在父组件中子组件标签上通过v-slot:插槽名=“变量”来接受数据

数组去重

1、 ES6-set

var arr  = [1,1,'true','true',true,true,15,15,false,false, undefined,
undefined, null,null, NaN,NaN,'NaN', 0, 0, 'a', 'a',{},{}];
 
function arr_unique1(arr){
return  [...new Set(arr)];
//或者
//return  Array.from(new Set(arr));
}
arr_unique1(arr); // (13)[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

Map去重

function arr_unique2(arr) {
  let map = new Map();
  let array = new Array();  // 数组用于返回结果
  for (let i = 0; i < arr.length; i++) {
    if(map .has(arr[i])) {  // 如果有该key值
      map .set(arr[i], true);
    } else {
      map .set(arr[i], false);   // 如果没有该key值
      array .push(arr[i]);
    }
  }
  return array ;
}

 console.log(arr_unique2(arr)); //(13) [1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

filter+indexOf

function arr_unique5(arr){
    return  arr.filter((val,index,item)=>{
    return item.indexOf(val) === index;
   });
}

arr_unique5(arr); // (12) [1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]

数组排序

function MaoPaoSort(arr){
        for(var i = 0;i<arr.length-1;i++) {
            for(var j = 0;j<arr.length-i-1;j++){
                if(arr[j]>arr[j+1]){
                    //把大的数字放到后面
                    var str = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = str;
                }
            }
        }
    }
    var arr = [3,5,1,2,7,8,4,5,3,4];
    //console.log(arr);[3,5,1,2,7,8,4,5,3,4];
    MaoPaoSort(arr);
    //console.log(arr);[1, 2, 3, 3, 4, 4, 5, 5, 7, 8]

插队排序

function InsertSort(arr) {
  let len = arr.length;
  let preIndex, current;
  for (let i = 1; i < len; i++) {
    preIndex = i - 1;
    current = arr[i];
    while (preIndex >= 0 && current < arr[preIndex]) {
      arr[preIndex + 1] = arr[preIndex];
      preIndex--;
    }
    arr[preIndex + 1] = current;
  }
  return arr;
}
 
 
var arr = [3,5,7,1,4,56,12,78,25,0,9,8,42,37];
InsertSort(arr);

上一篇:快速排序(萝卜填坑算法)【必会知识】


下一篇:使用Monkey进行软件测试(随机测试+脚本测试)