# fed-e-task-03-01 **Repository Path**: fed-e-task/fed-e-task-03-01 ## Basic Information - **Project Name**: fed-e-task-03-01 - **Description**: 大前端训练营第三部分模块一(vue基础实践使用) - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-12 - **Last Updated**: 2021-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 揭智勇 | Part 3 | 模块一 ## 简答题 ### 1、当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如果把新增成员设置成响应式数据,它的内部原理是什么。 ```javascript let vm = new Vue({ el: '#el' data: { o: 'object', dog: {} }, method: { clickHandler () { // 该 name 属性是否是响应式的 this.dog.name = 'Trump' } } }) // 不是 // vue只能拦截预先定义的对象属性,对于新增的name属性是不能拦截到的,所以不是响应式的 // 如果要设置成响应式的,可以这样 this.dog = { name: 'Trup} // 由于dog对象属性是预定义的,所有dog是响应式的,如果修改dog值,会触发set方法,在set方法中,会将新值进行walk,使新值的每个属性变成响应式的。 ``` ### 2、请简述 Diff 算法的执行过程 - diff的过程就是调用patch函数,接受新旧虚拟节点两个参数oldVnode,vnode - 对比新旧节点,如果不同(新旧节点不值得比较)则取oldVnode的真实dom的父元素,在父元素中插入vnode创建的真实dom,删除oldVnode对应的老dom;代码如下 ```javascript const elm = oldVnode.elm; const parent = api.parentNode(elm); createElm(vnode); // 创建真是dom,在vnode中的el属性挂载真是vnode对应的真实dom if (parent !== null) { api.insertBefore(parent, vnode.elm, api.nextSibling(elm)); removeVnodes(parent, [oldVnode], 0, 0); } ``` - 如果相同(新旧节点值得比较)调用patchVnode方法 ```javascript function patchVnode(oldVnode, vnode, insertedVnodeQueue) { var i, hook; if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) { i(oldVnode, vnode); } var elm = vnode.elm = oldVnode.elm; var oldCh = oldVnode.children; var ch = vnode.children; if (oldVnode === vnode) // 一致直接退出比较 return; if (vnode.data !== undefined) { for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); i = vnode.data.hook; if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode); } if (isUndef(vnode.text)) { // 新节点有定义text if (isDef(oldCh) && isDef(ch)) { if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue); } else if (isDef(ch)) { if (isDef(oldVnode.text)) api.setTextContent(elm, ''); addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { removeVnodes(elm, oldCh, 0, oldCh.length - 1); } else if (isDef(oldVnode.text)) { api.setTextContent(elm, ''); } } else if (oldVnode.text !== vnode.text) { // 新旧节点文本值不同 api.setTextContent(elm, vnode.text); } if (isDef(hook) && isDef(i = hook.postpatch)) { i(oldVnode, vnode); } } ``` - patchVnode方法对比新旧节点存在5中情况如下 1. 如果新旧节点引用一致及oldVnode === vnode,则退出 2. 如果新旧节点文本值不同,则直接改变真实dom的文本值为新节点的文本值,调用api.setTextContent(elm, vnode.text); 3. 如果新旧节点都有子节点,而且不同,调用updateChildren(elm, oldCh, ch, insertedVnodeQueue);比较子节点 4. 如果只有新节点有子节点,调用 addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);添加子节点 5. 如果旧节点有子节点,新节点没有子节点,移除旧的子节点,调用 removeVnodes(elm, oldCh, 0, oldCh.length - 1); - 如果新旧节点都有子节点,而且不同调用 updateChildren方法比较子元素 ## 编程题 ### 1、模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。 - 代码见code/vue-hash-router目录 - 实现思路 ### 2、在模拟 Vue.js 响应式源码的基础上实现 v-html 指令,以及 v-on 指令 - 代码见code/miniVue ### 3、参考 Snabbdom 提供的电影列表的示例,利用Snabbdom 实现类似的效果,如图: ![](https://s0.lgstatic.com/i/image/M00/26/F2/Ciqc1F7zUZ-AWP5NAAN0Z_t_hDY449.png) - 代码见code/snabbdom-demo-list