zoukankan      html  css  js  c++  java
  • Vue2源码解读(4)

    Vue2源码解读 - 响应式原理及简单实现

    直接进入主题了,想必大家都知道实现vue响应式核心方法就是 Object.defineProperty,那就从它开始说

    Object.defineProperty

    缺点:

    • 深度监听,需要递归到底,一次性计算量大
    • 无法监听新增、删除属性(需要vue.set 和 vue.delete)
    • 无法原生监听数组,需要特殊处理

    实现响应式

    function updateView () {
      console.log('视图更新')
    }
    
    // 重新定义数组原型
    const oldArrayProperty = Array.prototype
    // 创建新对象原型指向 Array.prototype,在扩展新的方法不会影响原型
    const arrProto = Object.create(oldArrayProperty);
    ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
      arrProto[methodName] = function () {
        updateView()
        oldArrayProperty[methodName].call(this, ...arguments)
      } 
    });
    
    // 监听data传入的属性
    function defineReactive(target, key, value) {
      // 深度监听 多层对象嵌套
      observer(value)
      // 核心api
      Object.defineProperty(target, key, {
        get() {
          return value
        },
    
        set(newVal) {
          // 设置新值也要监听 比如{age:27}
          observer(newVal)
          if (newVal !== value ) {
            value = newVal
            updateView()
          }
        }
      })
    }
    // 监听对象属性
    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        // 不是对象或数组
        return target
      }
      // 监听数组 把原数组的隐式原型赋值给我们定义好的数组对象
      if (Array.isArray(target)) {
        target.__proto__ = arrProto
      }
      // 重新定义各个属性,加getter、setter属性
      for(let key in target) {
        defineReactive(target, key, target[key])
      }
    }
    
    const data = {
      name: 'zk',
      age: 26,
      info: {
        address: 'city'  // 需深度监听
      },
      nums: [1, 2, 3]
    }
    observer(data)
    // data.info.address = 'beijing' // 需要深度监听
    // data.info = {address:'beijing'} // 需要深度监听
    // data.x = 666                  // 新增属性,监听不到  需要vue.set方法 
    // delete data.name              // 删除属性,监听不到  需要vue.delete方法 
    data.nums.push(21)
    

    vue2简单的数据双向绑定实现

    <div>内容:<span id="content"></span></div>
    <input id="iptName" />
    
    const iptName = document.getElementById('iptName')
    const content = document.getElementById('content')
    let obj = {
      name: ''
    }
    let newObj = JSON.parse(JSON.stringify(obj))
    Object.defineProperty(obj, 'name', {
      get() {
        return newObj.name
      },
    
      set(val) {
        if (val === newObj.name) return
        newObj.name = val
        observer()
      }
    })
    function observer () {
      iptName.innerText = obj.name
      content.innerText = obj.name
    }
    iptName.oninput = function () {
      obj.name = this.value
    }
    
  • 相关阅读:
    Java实现第九届蓝桥杯第几个幸运数字
    Java实现第九届蓝桥杯第几个幸运数字
    Java实现第九届蓝桥杯字母阵列
    Java实现第九届蓝桥杯字母阵列
    为什么mysql设置了密码之后,本地还可以直接访问,不需要输入密码就可以登录数据库了?
    centos7破解mariadb密码
    centos7使用无线wifi连接
    centos7中firewall防火墙命令详解
    CentOS 7 为firewalld添加开放端口及相关资料
    Mysql中较为复杂的分组统计去重复值
  • 原文地址:https://www.cnblogs.com/shizk/p/15456247.html
Copyright © 2011-2022 走看看