# fed-e-task-03-01 **Repository Path**: zhen_lili/fed-e-task-03-01 ## Basic Information - **Project Name**: fed-e-task-03-01 - **Description**: 《手写 Vue Router、手写响应式实现、虚拟 DOM 和 Diff 算法》 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-15 - **Last Updated**: 2023-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 一、简答题 #### 1、当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如何把新增成员设置成响应式数据,它的内部原理是什么。 ``` js let vm = new Vue({ el: '#el' data: { o: 'object', dog: {} }, method: { clickHandler() { // 该 name 属性是否是响应式的 this.dog.name = 'Trump' } } }) ``` 不是响应式的 对于已经创建的实例, Vue 不允许动态添加根级别的响应式 property 在创建vue实例的时候, 已经遍历data属性并且给每一个属性设置了响应式机制, getter/setter响应式机制, 在gette中收集依赖保留观察者初始值,数据变化触发set的dep类的notify方法遍历所有依赖这个变化属性的watcher,调用观察者的update方法更新视图, 新增成员设置成响应式数据 重新唤起Observer类对新增属性设置getter/setter ``` js Vue.set(dog, 'name', 'Trump') ``` #### 2、请简述 Diff 算法的执行过程 * diff 算法的核心,对比新旧节点的 children,更新 DOM * 要对比两棵树的差异,我们可以取第一棵树的每一个节点依次和第二课树的每一个节点比 较,但是这样的时间复杂度为 O(n^3) * 因此只需要找同级别的子节点依次比较,然后再找下一级别的节点比较,这样算法的时间复 杂度为 O(n) * 在进行同级别节点比较的时候,首先会对新老节点数组的开始和结尾节点设置标记索引,遍历的过程中移动索引 * 在对开始和结束节点比较的时候,总共有四种情况 - oldStartVnode / newStartVnode (旧开始节点 / 新开始节点) - oldEndVnode / newEndVnode (旧结束节点 / 新结束节点) - oldStartVnode / oldEndVnode (旧开始节点 / 新结束节点) - oldEndVnode / newStartVnode (旧结束节点 / 新开始节点) - oldStartVnode / newStartVnode (旧开始节点 / 新开始节点),如果 sameVnode (key 和 sel 相同) , 调用 patchVnode() 对比和更新节点,然后更新索引 oldStartIdx++ / oldEndIdx++ - oldEndVnode / newEndVnode (旧开始节点 / 新开始节点),如果 sameVnode (key 和 sel 相同) , 调用 patchVnode() 对比和更新节点,然后更新索引 oldEndIdx-- / oldEndIdx-- - oldStartVnode / newEndVnode (旧开始节点 / 新结束节点) 调用 patchVnode() 对比和更新节点,把 oldStartVnode 对应的 DOM 元素,移动到当前oldEndIdx的后面,然后更新索引 oldStartIdx++ / newEndIdx-- - oldEndVnode / newStartVnode (旧结束节点 / 新开始节点) 相同,调用 patchVnode() 对比和更新节点,把 oldEndVnode 对应的 DOM 元素,移动到当前oldStartIdx的前面,oldEndIdx-- / newStartIdx++ - 如果比较开始节点和结束节点都不相同 - 遍历新节点,使用 newStartNode 的 key 在老节点数组中找相同key - 如果没有找到,说明 newStartNode 是新节点,创建新节点对应的 DOM 元素,插入到 DOM 树中, newStartIdx++ - 如果找到了,判断新节点和找到的老节点的 sel 选择器是否相同,如果不相同,说明节点被修改了,重新创建对应的 DOM 元素,插入到 DOM 树中,如果相同,把 elmToMove 对应的 DOM 元素,移动到当前oldStartVnode的前面,newStartIdx++ - 循环结束存在两种情况,旧的子节点先遍历完还是新的子节点先遍历完 - 当老节点的所有子节点先遍历完 (oldStartIdx > oldEndIdx) - 新节点有剩余,把新节点的剩余节点批量 插入到oldEndIdx的末尾 - 新节点的所有子节点先遍历完 (newStartIdx > newEndIdx) 说明老节点有剩余,把剩余节点批 量删除 ### 二、编程题 #### 1、模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。 [vueRouter作业链接](https://gitee.com/zhen_lili/fed-e-task-03-01/tree/master/code/hash%E8%B7%AF%E7%94%B1) #### 2、在模拟 Vue.js 响应式源码的基础上实现 v-html 指令,以及 v-on 指令。 [模拟响应式作业链接](https://gitee.com/zhen_lili/fed-e-task-03-01/tree/master/code/%E6%A8%A1%E6%8B%9F%E5%93%8D%E5%BA%94%E5%BC%8F) #### 3、参考 Snabbdom 提供的电影列表的示例,利用Snabbdom 实现类似的效果,如图: [Snabbdom电影列表作业链接](https://gitee.com/zhen_lili/fed-e-task-03-01/tree/master/code/reorder-animation) [笔记在pdf的基础上做的](https://gitee.com/zhen_lili/fed-e-task-03-01/tree/master/notes)