# fed-e-task-03-01 **Repository Path**: mxydl2009/fed-e-task-03-01 ## Basic Information - **Project Name**: fed-e-task-03-01 - **Description**: 拉勾教育大前端高薪训练营 002 期作业仓库,阶段三,模块一 Vue-Router原理与实现、Vue响应式原理与实现、Vue的virtual DOM库snabbdom原理与源码分析 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-22 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # fed-e-task-03-01 ## 介绍 拉勾教育大前端高薪训练营 002 期作业仓库,阶段三,模块一 Vue-Router原理与实现、Vue响应式原理与实现、Vue的virtual DOM库snabbdom原理与源码分析 ## 简答题 #### 1. 当我们点击按钮的时候动态给data增加的成员是否是响应式数据,如果不是的话,如果把新增成员设置成响应式数据,它的内部原理是什么。 ``` let vm = new Vue({ el: '#el', data: { o: 'object', dog: {} }, method: { clickHandler () { // 该name属性是否是响应式的 this.dog.name = 'Trump' } } }) ``` 动态增加的data成员不是响应式数据,因为动态增加的成员调用Object.defineProperty方法,没有收集依赖,无法在数据更新时自动视图。 如果是添加嵌套对象的响应式成员,则只要调用Object.defineProperty即可。 使用`Vue.set(object, propertyName, value)`可以给data的嵌套对象增加响应式成员,例如`Vue.set(vm.dog, 'name', 'Trump')`。其原理是使用defineProperty方法将嵌套对象的新增成员定义为响应式数据,同时收集依赖,创建watcher。 #### 2. 请简述Diff算法的执行过程 Diff算法是用来比较两棵树同一层级节点的差异,进而使用最小的操作次数将旧树映射为新树。 在比较时,需要分别遍历两棵树, 遍历的原则: - 以旧树为准判断与新树的差异,从旧树的一端开始逐个与新树的两端比较,如旧树的开始节点与新树的开始节点比较、旧树的结束节点与新树的结束节点比较,旧树的开始节点与新树的结束节点比较,旧树的结束节点与新树的开始节点比较。 - 通过两端这4种分别比较,就可以确定两棵树的两端节点是否有相同,如果没有相同,则需要从旧树的中间节点中寻找新树的开始节点。 - 中间节点的查询使用key属性帮助查询,一旦在旧树中找到新树的开始节点,则判断是否类型一样,如果一样则移动节点,如果不一样,则创建并插入节点。如果在旧树中找不到新树的开始节点,则创建并插入节点。中间查询的方式因为不涉及旧树的两端节点,所以更新节点索引只需要将新树的开始节点索引更新即可。 - 两端比较和中间查询做完后,一轮的比较就结束了,更新索引后继续下一轮的比较 对两棵树同层级节点使用oldStartIndex和oldEndIndex,newStartIndex和newEndIndex分别标记首尾节点,便于遍历。 遍历过程如下 1. 开始遍历,会有以下四种互斥情况,如果不满足当前情况,则按顺序依次执行。每次比较后如果相同,则patchNode,然后开启新一轮的遍历。 - oldStartIndex节点与newStartIndex节点比较,如果相同,则patchNode,分别增加索引值oldStartIndex和newStartIndex - oldEndIndex节点与newEndIndex节点比较,如果相同,则patchNode,分别减少索引值oldEndIndex和newEndIndex - oldStartIndex节点与newEndIndex节点比较,如果相同,则patchNode,将oldStartIndex移动到最后,增加索引值oldStartIndex,减少索引值newEndIndex - oldEndIndex节点与newStartIndex节点比较,如果相同,则patchNode,将oldEndIndex节点移动到最前,减少索引值oldEndIndex,增加索引值newStartIndex 2. 如果遍历中以上四种情况都不满足,则会使用key属性进行查询 - 如果newStartIndex节点的key在旧树上没查到,表示这是一个新的节点,则创建该节点,并移动到oldStartIndex之前,增加newStartIndex索引值 - 如果newStartIndex节点的key在旧树上查到,但newStartIndex节点类型与旧树上对应的节点类型不一致,则认为也是一个新节点,创建该节点,并移动到oldStartIndex之前,增加newStartIndex索引值 - 如果newStartIndex节点的key在旧树上查到,且newStartIndex节点与旧树上对应的节点类型一致,表示这两个节点相同,则patchNode,移动旧树上的节点到oldStartIndex节点之前,将原来旧树上该索引位置的节点置空,增加newStartIndex索引值 3. 遍历完成后,需要判断旧树先完成还是新树先完成,根据谁先完成来针对性操作 - 旧树先完成遍历,表示旧树的节点少于新树,那么新树中未参与遍历的节点则统一移动到(newEndIdx+1)索引对应的节点之前 - 新树先完成遍历,表示新树的节点少于旧树,那么旧树中未参与遍历的节点则统一移除 ## 编程题 1. 见vue-router-hash文件夹 2. 见vue-simulation文件夹 3. 见snabbdom-movies文件夹