part3_模块一作业

12 篇文章 1 订阅

一、简答题

1、当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如何把新增成员设置成响应式数据,它的内部原理是什么。

let vm = new Vue({
 el: '#el'
 data: {
  o: 'object',
  dog: {}
 },
 method: {
  clickHandler () {
   // 该 name 属性是否是响应式的
   this.dog.name = 'Trump'
  }
 }
})

解答:
不是响应式的,在Vue初始化的过程中将data选项中的值利用Object.defineProperty 中的 get/set 将其转化为响应式。新增成员不是响应式。
利用Vue.$set()将其转化为响应式。实现原理还是利用了Vue的Observer将其属性设置为响应式。

2、请简述 Diff 算法的执行过程

解答:

  • diff 的过程就是调用名为 patch 的函数,比较新旧节点,一边比较一边给真实的 DOM 打补丁
  • patch 函数接收两个参数 oldVnode 和 Vnode 分别代表新的节点和之前的旧节点,这个函数会比较 oldVnode 和 vnode 是否是相同的, 即函数 sameVnode(oldVnode, vnode), 根据这个函数的返回结果分如下两种情况:
    • true:则执行 patchVnode
    • false:则用 vnode 替换 oldVnode
  • patchVnode 这个函数做了以下事情:
    • 找到对应的真实 dom,称为 el
    • 判断 vnode 和 oldVnode 是否指向同一个对象,如果是,那么直接 return
    • 如果他们都有文本节点并且不相等,那么将 el 的文本节点设置为 vnode 的文本节点。
    • 如果 oldVnode 有子节点而 vnode 没有,则删除 el 的子节点
    • 如果 oldVnode 没有子节点而 vnode 有,则将 vnode 的子节点真实化之后添加到 el
    • 如果两者都有子节点,则执行 updateChildren 函数比较子节点,这一步很重要
      • 给新老节点定义开始、结束索引
      • 循环比对新节点开始VS老节点开始、新节点结束VS老节点结束、新节点开始VS老节点结束、新节点结束VS老节点开始并移动对应的索引,向中间靠拢根据新节点的key在老节点中查找,没有找到则创建新节点。
      • 循环结束后,如果老节点有多的,则删除。如果新节点有多的,则添加。

二、编程题

1、模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。

let _Vue = null
export default class VueRouter {
  static install (vue) {
    // 1 判断当前插件是否被安装
    if (VueRouter.install.installed) return
    VueRouter.install.installed = true
    // 2 把Vue的构造函数记录在全局
    _Vue = vue
    // 3 把创建Vue的实例传入的router对象注入到Vue实例
    // _Vue.prototype.$router = this.$options.router
    _Vue.mixin({
      beforeCreate () {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
        }
      }
    })
  }

  constructor (options) {
    this.mode = options.mode || "hash"
    this.routes = options.routes
    this.routeMap = {}
    // observable
    this.data = _Vue.observable({
      current: '/'
    })
    this.init()
  }
  init () {
    this.initRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }
  initRouteMap () {
    //遍历所有路由信息,把组件和路由的映射记录到 routeMap 对象中
    this.routes.forEach( route => {
      this.routeMap[route.path] = route.component
    })
  }
  initComponent(Vue){
    //创建 router-link 和 router-view 组件
    const self = this
    Vue.component('router-link',{
      props:{
        to:String
      },
      render(h){
        return h("a",{
          attrs:{
            href: self.mode === "history" ? "" : "#" + this.to
          },
          on:{
            click:self.mode === "history" ? this.clickhander : this.hashClickhander
          }
        },[this.$slots.default])
      },
      methods:{
        clickhander(e){
          history.pushState({},"",this.to)
          this.$router.data.current=this.to
          e.preventDefault()
        },
        hashClickhander(e){
          this.$router.data.current=this.to
        }
      }
      // template:"<a :href='to'><slot></slot><>"
    })

    Vue.component('router-view',{
      render(h){
        let cm = self.routeMap[self.data.current]
        return h(cm)
      }
    })
  }
  initEvent(){
    //注册 popstate 事件,当路由地址发生变化,重新记录当前的路径
    const eventType = this.mode === 'history' ? 'popstate' : 'hashchange'
    const handle = this.mode === 'history' ? this.getLocation : this.getHash
    window.addEventListener(eventType,handle.bind(this))
  }
  getLocation(){
    this.data.current = window.location.pathname
  }
  getHash(){
    let href = window.location.href
    const index = href.indexOf('#')
    if (index < 0) return '/'
    this.data.current = href.slice(index + 1)
  }
}

2、在模拟 Vue.js 响应式源码的基础上实现 v-html 指令,以及 v-on 指令。
解答:作业地址:
https://github.com/myxiangdong/minivue

3、参考 Snabbdom 提供的电影列表的示例,利用Snabbdom 实现类似的效果,如图:
在这里插入图片描述
解答:作业地址:
https://github.com/myxiangdong/snabbdom-demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值