设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 重新 试卷 文件
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

中高级前端大厂面试秘籍,为你保驾护航金三银四,直通大厂(13)

发布时间:2019-02-20 20:16 所属栏目:21 来源:佚名
导读:对比属性(对比新旧属性列表): 旧属性是否存在与新属性列表中 都存在的是否有变化 是否出现旧列表中没有的新属性 tagName 和 key 值变化了,则直接替换成新节点 渲染差异 遍历 patchs , 把需要更改的节点取出来 局

对比属性(对比新旧属性列表):

  • 旧属性是否存在与新属性列表中
  • 都存在的是否有变化
  • 是否出现旧列表中没有的新属性
  • tagNamekey值变化了,则直接替换成新节点
  • 渲染差异

    • 遍历patchs, 把需要更改的节点取出来
    • 局部更新dom
    1. // diff算法的实现 
    2. function diff(oldTree, newTree) { 
    3.      // 差异收集 
    4.     let pathchs = {} 
    5.     dfs(oldTree, newTree, 0, pathchs) 
    6.     return pathchs 
    7.  
    8. function dfs(oldNode, newNode, index, pathchs) { 
    9.     let curPathchs = [] 
    10.     if (newNode) { 
    11.         // 当新旧节点的 tagName 和 key 值完全一致时 
    12.         if (oldNode.tagName === newNode.tagName && oldNode.key === newNode.key) { 
    13.               // 继续比对属性差异 
    14.             let props = diffProps(oldNode.props, newNode.props) 
    15.             curPathchs.push({ type: 'changeProps', props }) 
    16.             // 递归进入下一层级的比较 
    17.             diffChildrens(oldNode.children, newNode.children, index, pathchs) 
    18.         } else { 
    19.               // 当 tagName 或者 key 修改了后,表示已经是全新节点,无需再比 
    20.             curPathchs.push({ type: 'replaceNode', node: newNode }) 
    21.         } 
    22.     } 
    23.  
    24.      // 构建出整颗差异树 
    25.     if (curPathchs.length) { 
    26.             if(pathchs[index]){ 
    27.                 pathchs[index] = pathchs[index].concat(curPathchs) 
    28.             } else { 
    29.                 pathchs[index] = curPathchs 
    30.             } 
    31.     } 
    32.  
    33. // 属性对比实现 
    34. function diffProps(oldProps, newProps) { 
    35.     let propsPathchs = [] 
    36.     // 遍历新旧属性列表 
    37.     // 查找删除项 
    38.     // 查找修改项 
    39.     // 查找新增项 
    40.     forin(olaProps, (k, v) => { 
    41.         if (!newProps.hasOwnProperty(k)) { 
    42.             propsPathchs.push({ type: 'remove', prop: k }) 
    43.         } else { 
    44.             if (v !== newProps[k]) { 
    45.                 propsPathchs.push({ type: 'change', prop: k , value: newProps[k] }) 
    46.             } 
    47.         } 
    48.     }) 
    49.     forin(newProps, (k, v) => { 
    50.         if (!oldProps.hasOwnProperty(k)) { 
    51.             propsPathchs.push({ type: 'add', prop: k, value: v }) 
    52.         } 
    53.     }) 
    54.     return propsPathchs 
    55.  
    56. // 对比子级差异 
    57. function diffChildrens(oldChild, newChild, index, pathchs) { 
    58.         // 标记子级的删除/新增/移动 
    59.     let { change, list } = diffList(oldChild, newChild, index, pathchs) 
    60.     if (change.length) { 
    61.         if (pathchs[index]) { 
    62.             pathchs[index] = pathchs[index].concat(change) 
    63.         } else { 
    64.             pathchs[index] = change 
    65.         } 
    66.     } 
    67.  
    68.      // 根据 key 获取原本匹配的节点,进一步递归从头开始对比 
    69.     oldChild.map((item, i) => { 
    70.         let keyIndex = list.indexOf(item.key) 
    71.         if (keyIndex) { 
    72.             let node = newChild[keyIndex] 
    73.             // 进一步递归对比 
    74.             dfs(item, node, index, pathchs) 
    75.         } 
    76.     }) 
    77.  
    78. // 列表对比,主要也是根据 key 值查找匹配项 
    79. // 对比出新旧列表的新增/删除/移动 
    80. function diffList(oldList, newList, index, pathchs) { 
    81.     let change = [] 
    82.     let list = [] 
    83.     const newKeys = getKey(newList) 
    84.     oldList.map(v => { 
    85.         if (newKeys.indexOf(v.key) > -1) { 
    86.             list.push(v.key) 
    87.         } else { 
    88.             list.push(null) 
    89.         } 
    90.     }) 
    91.  
    92.     // 标记删除 
    93.     for (let i = list.length - 1; i>= 0; i--) { 
    94.         if (!list[i]) { 
    95.             list.splice(i, 1) 
    96.             change.push({ type: 'remove', index: i }) 
    97.         } 
    98.     } 
    99.  
    100.     // 标记新增和移动 
    101.     newList.map((item, i) => { 
    102.         const key = item.key 
    103.         const index = list.indexOf(key) 
    104.         if (index === -1 || key == null) { 
    105.             // 新增 
    106.             change.push({ type: 'add', node: item, index: i }) 
    107.             list.splice(i, 0, key) 
    108.         } else { 
    109.             // 移动 
    110.             if (index !== i) { 
    111.                 change.push({ 
    112.                     type: 'move', 
    113.                     form: index, 
    114.                     to: i, 
    115.                 }) 
    116.                 move(list, index, i) 
    117.             } 
    118.         } 
    119.     }) 
    120.  
    121.     return { change, list } 

    5. Proxy 相比于 defineProperty 的优势

    • 数组变化也能监听到
    • 不需要深度遍历监听
    1. let data = { a: 1 } 
    2. let reactiveData = new Proxy(data, { 
    3.     get: function(target, name){ 
    4.         // ... 
    5.     }, 
    6.     // ... 
    7. }) 

     

    • mode

      • hash
      • history
    • 跳转

      • this.$router.push()
      • <router-link to=""></router-link>
    • (编辑:ASP站长网)

    网友评论
    推荐文章
      热点阅读