vue2的实现(6)之将数据代理到Vue的实例上

143 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

vue2的实现(6)之将数据代理到Vue的实例上

回顾

  • 上次内容我们处理了一个问题,假如用户传入的数据data,是深层嵌套的,那我们之前写的逻辑就劫持不到用户的操作,所以我们需要在rewrite-vue/src/observe/index.js中的defineReactive方法中,再次对对象的每个属性值进行监测,我们只需要每次在对传入的value进行observe(value)操作即可。这样我们就可以进行深层递归劫持了,下面是我们上次完成的代码。

  • rewrite-vue/src/observe/index.js

    class Observe {
      consturctor(data){
        this.walk(data)
      }
    
      walk(data){
        Object.keys(data).forEach(key => defineReactive(data, key, data[key]))
      }
    }
    
    export function defineReactive(target, key, value){
      observe(value)
      Object.defineProperty(target, key, {
        get(){
          console.log('劫持用户的取值操作,get');
          return value
        },
        set(newValue){
          if(newValue !== value){
            console.log('劫持用户的设置操作,set');
            observe(newValue)
            value = newValue
          }
        }
      })
    }
    
    
    export function observe(data){
      if(typeof data !== 'object' || data === null){
        return 
      }
      return new Observe(data)
    }
    

如何将数据代理到Vue的实例上

  • 我们用下面的代码测试一下,在浏览器打开rewrite-vue/dist/index.html

  • rewrite-vue/dist/index.html

      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Vue2</title>
      </head>
      <body>
      <script src="./vue.js"></script>
      <script>
          const vm = new Vue({
            data:{
                name:'vue2',
                age: {
                  num:666,
                  key:'age'
                }
              }
          })
          console.log(vm.name);
      </script>
      </body>
      </html>
    
  • 下面的图片是输出结果,我们可以看到打印的结果是undefined

  • 我们在使用Vue的时候,可以从实例上直接访问到数据data,而不需要从vm._data去取值。

    2022-01-30-1.png

  • 当我们访问vm实例上的属性的时候,我们需要把他代理到_data上。

  • 因为这个操作属于处理数据的操作,和我们的observe模块并不是一个模块。所以我们把他放到rewrite-vue/src/state.js中,在我们初始化数据的initData方法中去做。

  • 我们写一个专门的方法来做这件事情,这个方法叫做proxyproxy方法接受两个参数,一个是vm实例,一个是我们在vm访问属性时,要代理的目标对象的名称,这个方法我们以后也可以用来代理propscomputed

  • proxy方法的作用就是,循环遍历所有的目标对象属性,把所有的属性代理到vm实例上。

  • rewrite-vue/src/state.js

      import {observe} from './observe'
    
      export  function initState(vm) {
      const opts = vm.$options
    
    
          if (opts.data) {
          initData(vm)
          }
      }
    
    
      function initData(vm) {
          let data = vm.$options.data
          data = typeof data === 'function'? data.call(vm) : data
          vm._data = data
          proxy(vm, '_data')
          observe(data)
      } 
    
      function proxy(vm, target){
          for(let key in vm[target]){
              Object.defineProperty(vm,key,{
                  get(){
                      return vm[target][key]
                  },
                  set(newValue){
                      vm[target][key] = newValue
                  }
              })
          }
      }
    

测试

  • rewrite-vue/dist/index.html里面的代码还是上面的测试用例,我们再次在浏览器中打开rewrite-vue/dist/index.html

  • 从下面的图可以看出我们的打印已经生效了,证明我们已经把_data属性代理到了vm实例上。 2022-01-30-2.png 今天是更文第十三天加油~ 看到这里兄弟帮忙点个赞吧

往期精彩

vue2的实现(5)之对象劫持的一些细节处理二

vue2的实现(4)之对象劫持的一些细节处理一

vue2的实现(3)之对象的劫持

vue2的实现(2)之初始化数据data

vue2的实现(1)之搭建rollup打包环境

手撕koa,从零掌握koa的实现原理(1)

手撕koa,从零掌握koa的实现原理(2)

手撕koa,从零掌握koa的实现原理(3)

手撕koa,从零掌握koa的实现原理(4)

手撕koa,从零掌握koa的实现原理(5)

手撕koa,从零掌握koa的实现原理(6)

手撕koa,从零掌握koa的实现原理(7)