Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue 如何监听一个对象和数组的变化 #12

Closed
hitao123 opened this issue Feb 24, 2019 · 0 comments
Closed

Vue 如何监听一个对象和数组的变化 #12

hitao123 opened this issue Feb 24, 2019 · 0 comments
Labels

Comments

@hitao123
Copy link
Owner

监听一个对象和数组的变化

大家可能对 vue 使用 defineProperty 方法来实现底层双向绑定也很熟悉了,下面简单实现一下简单的监听一个对象和数组的变化

/**
 * 检测对象属性被更改
 */

const ARRAY = 0;
const OBJECT = 1;

/**
 * 数组变异方法
 * 这几个方法会改变原来数组
 */
const arrayAugmentations = [];
const aryMethods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
];

aryMethods.forEach(method => {
  let original = Array.prototype[method];
  arrayAugmentations[method] = function() {
    let result = original.apply(this, arguments);
    console.log('🍺 我是数组我被设置了', result)
    return result;
  };
});

/**
 * 对象添加新属性
 * @param {*} data 
 * @param {*} type 
 * 
 */
const objectAugmentations = {};

Object.defineProperty(objectAugmentations, '$add', {
  value: function(key, value) {
    if (this.hasOwnProperty(key)) return;
    Object.defineProperty(this, key, {
      configurable: true,
      get: function() {
        console.log('💖 我被获取了 我的值是', value)
        return value
      },
      set: function(val) {
        console.log('🐂 我被设置了 我设置的新值是', val)
        if (val === value) return
        value = val;
        return value
      }
    });
  },
  configurable: true,
});

Object.defineProperty(objectAugmentations, '$delete', {
  value: function(key) {
    if (!this.hasOwnProperty(key)) return;
    console.log('⛰ 我被删除了', key)
    delete this[key];
  },
  configurable: true,
  writable: true
});


function Observer(data, type) {
  if (!(this instanceof Observer)) throw Error('should be called by new')
  this.data = data;
  console.log(data, '===>');
  if (type === ARRAY) {
    data.__proto__ = arrayAugmentations; // eslint-disable-line
    this.link(data);
  } else if (type === OBJECT) {
    data.__proto__ = objectAugmentations; // eslint-disable-line
    this.walk(data);
  }
};

Observer.prototype.walk = function(data) {
  if (typeof data !== 'object') return;
  for(key in data) {
    if (data.hasOwnProperty(key)) {
      let value = data[key];
      if (typeof value == 'object') {
        Observer.create(value)
      }
      this.convert(key, value);
    }
  }
}

Observer.prototype.link = function(items) {
  items.forEach((value) => {
    let ob = Observer.create(value);
    if (!ob) return;
  });
};

Observer.prototype.convert = function(key, value) {
  console.log(key)
  Object.defineProperty(this.data, key, {
    configurable: true,
    enumerable: true,
    get: function() {
      console.log('💖 我被获取了 我的值是', value)
      return value
    },
    set: function(val) {
      console.log('🐂 我被设置了 我设置的新值是', val)
      if (val === value) return
      value = val;
      return value
    }
  });
}

/**
 * 根据不同的数据类型,调用observer构造函数
 * @param value {Any} 数据
 * @returns {Observer}
 */
Observer.create = function(value) {
  if (Array.isArray(value)) {
    return new Observer(value, ARRAY);
  } else if (typeof value === 'object') {
    return new Observer(value, OBJECT);
  }
};




let data = {
  a: 1,
  b: {
    c: {
      d: 3
    }
  },
  arr: [4, 5]
}

let app = Observer.create(data);

console.log()
console.log('====start==')
console.log(data.a);
data.a = 'aaa';
console.log(data.a)
console.log()
console.log(data.b.c.d);
data.b.c.d = 'dddd';
console.log(data.b.c.d)
console.log()
console.log(data.arr);
console.log()

console.log(data.arr.push(100))
console.log(data.arr)
console.log()
console.log(app.data.$add('age', 25))
console.log(data.age)
console.log(app.data.$delete('age'))
console.log('====end==')

参考

@hitao123 hitao123 added the vue label Feb 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant