# fed-e-task-03-01 **Repository Path**: learning-summary/fed-e-task-03-01 ## Basic Information - **Project Name**: fed-e-task-03-01 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-21 - **Last Updated**: 2021-01-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.set或者this.$set来设置成响应式数据,其内部的原理其实还是通过Observer进行数据劫持和响应 ### 2、请简述 Diff 算法的执行过程 Diff算法主要是调用path的过程 **真正主要的还是pathVnode和updateChildren方法** **path调用过程中判断是相同节点后会调用pathVnode方法** 分为不是文本节点的情况和是文本节点的情况 - 不是文本节点 - 旧oldCh和新ch子节点都存在,两个子节点没指向同一个地址引用,就调用updateChildren方法 - 只有新ch存在,就往elm上添加新ch节点 - 只有旧oldCh存在就,从elm上移除旧oldCh节点 - 只有旧oldCh的text存在就将elm设置为'' - 文本节点并且不相等的情况下 - 如果旧oldCh存在就从elm上移除旧oldCh,然后给elm设置成新的vnode.text **最后是updateChildren方法** 主要分为主要阶段 第一阶段对比阶段 - 旧开始节点和新开始节点的对比 - 旧结束节点和新开始节点的对比 - 旧开始节点和新结束节点的对比 - 新开始节点和旧结束节点的对比 - 都不满足的话就查找相同key的节点,如果找到了就用找打的插入旧开始DOm之前,如果没找到就创建dom元素,然后插入旧dom开始之前 对比完成后更新节点,最后是收尾工作 旧节点或者新节点没有遍历完的时候,就会进行收尾 - 如果新节点有多余,就把剩余的新节点插入到旧节点右边 - 若干旧节点有多余,就删除掉多余的节点 ## 二、编程题 #### 1、模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。 ```js let _Vue = null export default class VueRouter { constructor (options) { // 实例化router的options this.options = options // 路由与组件的映射关系对象 this.routerMap = {} // 创建相响应式的current属性, 当前的路由名字 this.data = _Vue.observable({ current: this.initCurrentHash() }) } static install (Vue) { // 1.判断有没有安装vue-router if (this.install.installed) return this.install.installed = true // 2.挂载在全局 _Vue = Vue // 3.将实例化的router挂载vue原型上 这里可以获取到vue实例 Vue.mixin({ beforeCreate () { if (this.$options.router) { // 存在即代表是new Vue实例化的 Vue.prototype.$router = this.$options.router this.$options.router.init() } } }) } // 初始化方法 init () { this.createRouteMap() this.initComponent(_Vue) this.initEvent() } // 创建路由的映射关系 createRouteMap () { this.options.routes.forEach(route => { this.routerMap[route.path] = route.component }) } // 初始化组件 initComponent (Vue) { const self = this Vue.component('router-link', { props: { to: String }, methods: { clickEvent (e) { window.location.hash = this.to self.data.current = this.to e.preventDefault() } }, render (h) { return h('a', { attrs: { to: this.to }, on: { click: this.clickEvent } }, this.$slots.default) } }) Vue.component('router-view', { render (h) { const component = self.routerMap[self.data.current] return h(component) } }) } // 初始化hash initCurrentHash () { // 保证刷新还是当前页面 window.location.hash = window.location.hash || '#/' return window.location.hash.slice(1) } // 初始化事件 initEvent () { window.addEventListener('hashchange', () => { this.data.current = location.hash.slice(1) }) } } } } ('hashchange', () => { this.data.current = location.hash.slice(1) }) } } ``` #### 2、在模拟 Vue.js 响应式源码的基础上实现 v-html 指令,以及 v-on 指令。 主要代码,参考本地目录/code/03-vue基本结构/js/compiler.js ```js // 根据不同的指令调取不同的方法方便维护 update (node, key, attrName) { let eventType if (attrName.includes('on:')) { let arrtNameArr = attrName.split(':') attrName = arrtNameArr[0] eventType = arrtNameArr[1] } let fn = this[attrName + 'Updater'] fn && fn.call(this, node, this.vm[key], key, eventType) } // 处理v-html htmlUpdater (node, value, key) { node.innerHTML = value new Watcher(this.vm, key, (newValue) => { node.innerHTML = newValue }) } // 处理v-on事件,举例v-on:click="clickEvent" onUpdater(node, value, key, eventType) { // 如果事件类型不存在就return掉 if(!eventType) return if(typeof value !== 'function') return node.addEventListener(eventType, value) new Watcher(this.vm, key, (newValue) => { // node.removeEventListener(eventType, value) node.addEventListener(eventType, newValue) }) } ``` #### 3、参考 Snabbdom 提供的电影列表的示例,利用Snabbdom 实现类似的效果,如图: ![](https://s0.lgstatic.com/i/image/M00/26/F2/Ciqc1F7zUZ-AWP5NAAN0Z_t_hDY449.png) **index.html** ```html Snabbdom-demo
``` **07-movies.js** ```js ```