zoukankan      html  css  js  c++  java
  • Vue.set 解析

    一、前言

    Vue 的一个特点就是数据的双向绑定。

    在 Vue2.x 中使用的是 defineProperty 对数据进行的拦截监听,由于这种方式对 Object 和 Array 的拦截有缺陷。

    所以在 Vue2.x 中有全局的 Vue.set API 来对这个缺陷进行修正(对于 Array 来说也是部分)。

    二、什么时候使用

    1、Object 使用

    Object 在 data 初始化的时候,就已经有的属性,在后面修改是可以直接修改,并被监听到的。

    对于后面新添加的属性,这时需要用 Vue.set 来新增添加,set 会对这个新增的属性进行拦截。

    2、Array 使用

    由于 Array 的操作都是监听不到的,所以 Vue 里面是做了两个操作的。

    • 对几个常用的操作单独处理
    • 下标操作转换成 splice (回到上面)

    对 Array 几个操作的特殊处理是下面这样:

    // 路径:srccoreobserverarray.js
    
    const arrayProto = Array.prototype
    export const arrayMethods = Object.create(arrayProto)
    
    // 特殊处理的方法列表
    const methodsToPatch = [
      'push',
      'pop',
      'shift',
      'unshift',
      'splice',
      'sort',
      'reverse'
    ]
    
    /**
     * 拦截方法并抛出事件
     */
    methodsToPatch.forEach(function (method) {
      // 缓存原始方法
      const original = arrayProto[method]
      def(arrayMethods, method, function mutator (...args) {
        const result = original.apply(this, args)
        const ob = this.__ob__
        let inserted
        switch (method) {
          case 'push':
          case 'unshift':
            inserted = args
            break
          case 'splice':
            inserted = args.slice(2)
            break
        }
        if (inserted) ob.observeArray(inserted)
        // 通知更改
        ob.dep.notify()
        return result
      })
    })

    三、源码分析

    在 Vue 源码中,是把 set 放在 observer 中定义的。

    set 是对这些进行监听处理。

    // 路径:srccoreobserverindex.js
    
    /**
     * 给 Object set 属性,当不存在时新增并做拦截代理,已经存在的不做处理
     * Array 的下标处理转换成 splice
     */
    export function set (target: Array<any> | Object, key: any, val: any): any {
      if (process.env.NODE_ENV !== 'production' &&
        (isUndef(target) || isPrimitive(target))
      ) {
        warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
      }
      // 是数组,并且是已有的下标处理,转换成 splice
      if (Array.isArray(target) && isValidArrayIndex(key)) {
        target.length = Math.max(target.length, key)
        target.splice(key, 1, val)
        return val
      }
      // 是对象,并且是已有属性,不做处理
      if (key in target && !(key in Object.prototype)) {
        target[key] = val
        return val
      }
      const ob = (target: any).__ob__
      if (target._isVue || (ob && ob.vmCount)) {
        process.env.NODE_ENV !== 'production' && warn(
          'Avoid adding reactive properties to a Vue instance or its root $data ' +
          'at runtime - declare it upfront in the data option.'
        )
        return val
      }
      if (!ob) {
        target[key] = val
        return val
      }
      defineReactive(ob.value, key, val)
      ob.dep.notify()
      return val
    }

    这里定义后,在 global-api 中赋值给全局 Vue

    // 路径:srccoreglobal-apiindex.js
    
    // 下面是截取部分代码
    
    import { set} from '../observer/index'
    
    export function initGlobalAPI (Vue: GlobalAPI) {
        Vue.set = set
    }
  • 相关阅读:
    HihoCoder 1638 : 小Hi的天平 (2-sat+并查集)
    阿里云安全肖力:云上数据安全体系建设的六要素
    MaxCompute客户端(odpscmd)在windows命令行下查询中文乱码问题处理实践
    序列化方案选型对比
    亚洲唯一,阿里云SLB位列Gartner全球网络负载均衡市场前五
    阿里云OSS同城冗余存储技术解析
    OSS跨同城3AZ重磅发布,构造全面数据保护体系
    阿里云OSS同城冗余存储正式商业化,提供云上同城容灾能力
    云原生应用 Kubernetes 监控与弹性实践
    GIAC2019 演讲精选 | 面向未来的黑科技——UI2CODE闲鱼基于图片生成跨端代码
  • 原文地址:https://www.cnblogs.com/zhurong/p/14927358.html
Copyright © 2011-2022 走看看