zoukankan      html  css  js  c++  java
  • 手写Vue (1) 对象劫持

    1.引入我们手写的Vue 拿到配置数据

    import Vue from '../source/src/index';
    let vm = new Vue({
      el: '#app',
      data() {
        return {
          msg: 'hello',
          school: {
            name: 'zf',
            age: 10
          },
          arr: [1, 2, 3]
        }
      },
      computed: {
    
      },
      watch: {
    
      }
    })
    console.log(vm)
    // setTimeout(() => {
    //   vm.arr[0].push(100)
    //   console.log(vm)
    // }, 1000)

    2. 新建文件    source/src/index  

    在这个文件中 我们利用 ——init 这个方法 对 用户传入的数据进行初始化 传入配置信息

    function Vue(options) {
      // console.log(options)
      // 初始化vue
      this._init(options)
    }

    3. 在_init 方法中 我们可以先将  options 挂载到实例  再进行初始化数据操作 

    Vue.prototype._init = function (options) {
      // vue 的初始化
      let vm = this;
      // 将 options 挂载到实例
      vm.$options = options;
      //需要数据重新初始化
      initState(vm)
    }

    5. 新建 文件  observe/index 编写  initState  方法并且导出

    export function initState(vm) {
      console.log(vm)
    }

    在这里我们可以拿到 vue 的整个实例方法 

    6. 在initState  方法中 我们进行初始化  比如初始化 数据 初始化 计算属性 初始化 watch 

    export function initState(vm) {
      // 拿到option  存储起来
      let options = vm.$options;
      if (options.data) {
        // 初始化数据
        initData(vm)
      }
      if (options.computed) {
        // 初始化计算属性
        initComputed()
      }
      if (options.watch) {
        // 初始化watch
        initWatch()
      }
    }

    7. 初始化数据 在    initData  方法中 我们通过 传入实例的option 拿到数据 再判断 数据 是 函数 还是 对象 如果是函数 调用call 方法 拿到函数 返回值 如何不是直接返回数据 或者 空数据 

     let data = vm.$options.data
      // 判断是否是函数 取返回值
      data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}

    8. 拿到数据后 我们要对数据进行 监听 编写   observe  方法 监听数据 、

    function initData(vm) {
      let data = vm.$options.data
      // 判断是否是函数 取返回值
      data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
      observe(vm._data)
    }

    10 在  observe 方法中 要进行判断 看看数据是不是对象或者为空 如果不是 直接返回 如果是 返回一个  Observe 对象 

    export function observe(data) {
      // 不是对象或者是null
      if (typeof data !== 'object' || data === null) {
        return
      }
      return new Observe(data)
    }

    11. 编写这个  Observe 对象   新建文件 Observe.js

    这个文件里面最主要的是   Object.defineProperty 方法 里面传入 data , 还有key  key 代表属性 所以 我们需要遍历数据 拿到 所有的 key value 传入 

    class Observe {
      constructor(data) {
        // 数组 重写push 方法
        if (Array.isArray()) {
        } else {
          // 对象
          // data 就是我们 定义的 vm._data 的数据
          this.walk(data)
        }
      }
      //将对象的数据使用 defineProperty 重新定义 
      walk(data) {
        let keys = Object.keys(data);
        for (let i = 0; i < keys.length; i++) {
          let key = keys[i];  // key
          let value = data[keys[i]];  // value
          defineReactive(data, key, value)
        }
      }
    }
    export function defineReactive(data, key, value) {
      Object.defineProperty(data, key, {
        get() {
          // 有值
          return value;
        },
        set(newValue) {
          if (newValue !== value) return;
          value = newValue
        }
      })
    }
    export default Observe;

    11.  因为 数据里面 的对象 可能嵌套 一个对象 所以我们应该在 数据里面的对象再进行 深度监听 

    
    
    import { observe } from './index'

    export function defineReactive(data, key, value) { observe(value); Object.defineProperty(data, key, {
    get() { // 有值 return value; }, set(newValue) { if (newValue !== value) return; value = newValue } }) }

    12. 测试代码 

    import Vue from '../source/src/index';
    let vm = new Vue({
      el: '#app',
      data() {
        return {
          msg: 'hello',
          school: {
            name: 'zf',
            age: 10
          },
          arr: [1, 2, 3]
        }
      },
      computed: {
    
      },
      watch: {
    
      }
    })
    console.log(vm._data.msg)  // hello

    打印出100 

    13.  这里每次取值都需要 挂在 _data 上  很 不方便 比如 

    vm._data.msg  我们简化为 vm.msg 
     
    所以 我们可以 利用  proxy 代理 _data  代理应该在 初始化数据 的操作中 监听数据前
    function initData(vm) {
      let data = vm.$options.data
      // 判断是否是函数 取返回值
      data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
      for (let key in data) {
        proxy(vm, "_data", key)
      }
      observe(vm._data)
    }

    14, 编写 proxy  方法

    function proxy(vm, source, key) {
      Object.defineProperty(vm, key, {
        get() {
          return vm[source][key]
        },
        set(newValue) {
          vm[source][key] = newValue
        }
      })
    }

    15。测试成功 

    import Vue from '../source/src/index';
    let vm = new Vue({
      el: '#app',
      data() {
        return {
          msg: 'hello',
          school: {
            name: 'zf',
            age: 10
          },
          arr: [1, 2, 3]
        }
      },
      computed: {
    
      },
      watch: {
    
      }
    })
    console.log(vm.msg)  // hello
  • 相关阅读:
    Log4net详细说明
    IDEA 介绍
    在互联网中关系型数据库是否不再那么重要
    彻底删除Kafka中的topic
    kafka consumer 配置详解
    kafka常用命令
    kafka可视化客户端工具Kafka Tool
    System.InvalidOperationException:“线程间操作无效: 从不是创建控件“btnSearch”的线程访问它。
    zookeeper图形化的客户端工具
    window上安装kafka(单机)
  • 原文地址:https://www.cnblogs.com/guangzhou11/p/12650360.html
Copyright © 2011-2022 走看看