Vue源码解析(二)

来源:互联网 发布:淘宝旺铺怎么用 编辑:程序博客网 时间:2024/05/19 02:42

接着看一下第二部分,调用stateMixin方法。

function stateMixin (Vue) {  // flow somehow has problems with directly declared definition object  // when using Object.defineProperty, so we have to procedurally build up  // the object here.  var dataDef = {};  dataDef.get = function () { return this._data };  var propsDef = {};  propsDef.get = function () { return this._props };  {    dataDef.set = function (newData) {      warn(        'Avoid replacing instance root $data. ' +        'Use nested data properties instead.',        this      );    };    propsDef.set = function () {      warn("$props is readonly.", this);    };  }  Object.defineProperty(Vue.prototype, '$data', dataDef);  Object.defineProperty(Vue.prototype, '$props', propsDef);  Vue.prototype.$set = set;  Vue.prototype.$delete = del;  Vue.prototype.$watch = function (    expOrFn,    cb,    options  ) {    var vm = this;    options = options || {};    options.user = true;    var watcher = new Watcher(vm, expOrFn, cb, options);    if (options.immediate) {      cb.call(vm, watcher.value);    }    return function unwatchFn () {      watcher.teardown();    }  };}

在Vue的原型上定义了几个属性,分别是$data、$props、$set、$delete、$watch。$data、$props是实例的data和props的代理,可读不可写。

function set (target, key, val) {  if (Array.isArray(target) && typeof key === 'number') {    target.length = Math.max(target.length, key);    target.splice(key, 1, val);    return val  }  if (hasOwn(target, key)) {    target[key] = val;    return val  }  var ob = (target ).__ob__;  if (target._isVue || (ob && ob.vmCount)) {    "development" !== '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$$1(ob.value, key, val);  ob.dep.notify();  return val}

set方法为设置动态数据,接受Object和Array两种类型,可以对数组插入或者或替换操作,也可以替换已有的object的内容,如果不存在则新生成一个可变化的数据。

function del (target, key) {  if (Array.isArray(target) && typeof key === 'number') {    target.splice(key, 1);    return  }  var ob = (target ).__ob__;  if (target._isVue || (ob && ob.vmCount)) {    "development" !== 'production' && warn(      'Avoid deleting properties on a Vue instance or its root $data ' +      '- just set it to null.'    );    return  }  if (!hasOwn(target, key)) {    return  }  delete target[key];  if (!ob) {    return  }  ob.dep.notify();}

delete方法删除数据中的动态参数,也接受Array和Object两种类型。

var Watcher = function Watcher (  vm,  expOrFn,  cb,  options) {  this.vm = vm;  vm._watchers.push(this);  // options  if (options) {    this.deep = !!options.deep;    this.user = !!options.user;    this.lazy = !!options.lazy;    this.sync = !!options.sync;  } else {    this.deep = this.user = this.lazy = this.sync = false;  }  this.cb = cb;  this.id = ++uid$2; // uid for batching  this.active = true;  this.dirty = this.lazy; // for lazy watchers  this.deps = [];  this.newDeps = [];  this.depIds = new _Set();  this.newDepIds = new _Set();  this.expression = expOrFn.toString();  // parse expression for getter  if (typeof expOrFn === 'function') {    this.getter = expOrFn;  } else {    this.getter = parsePath(expOrFn);    if (!this.getter) {      this.getter = function () {};      "development" !== 'production' && warn(        "Failed watching path: \"" + expOrFn + "\" " +        'Watcher only accepts simple dot-delimited paths. ' +        'For full control, use a function instead.',        vm      );    }  }  this.value = this.lazy    ? undefined    : this.get();};

watch方法是观察某个属性或者某个计算属性的变化,第一个参数为观察的内容,第二个为回调函数,返回新值和旧值,第三个为属性配置。watch方法主要实例化了一个Watcher对象。

Watcher.prototype.get = function get () {  pushTarget(this);  var value;  var vm = this.vm;  if (this.user) {    try {      value = this.getter.call(vm, vm);    } catch (e) {      handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));    }  } else {    value = this.getter.call(vm, vm);  }  // "touch" every property so they are all tracked as  // dependencies for deep watching  if (this.deep) {    traverse(value);  }  popTarget();  this.cleanupDeps();  return value};

watcher原型的get方法,获取watcher方法所观察的值(this.getter.call(vm,vm))。

Watcher.prototype.addDep = function addDep (dep) {  var id = dep.id;  if (!this.newDepIds.has(id)) {    this.newDepIds.add(id);    this.newDeps.push(dep);    if (!this.depIds.has(id)) {      dep.addSub(this);    }  }};

addDep方法,添加依赖。

Watcher.prototype.cleanupDeps = function cleanupDeps () {    var this$1 = this;  var i = this.deps.length;  while (i--) {    var dep = this$1.deps[i];    if (!this$1.newDepIds.has(dep.id)) {      dep.removeSub(this$1);    }  }  var tmp = this.depIds;  this.depIds = this.newDepIds;  this.newDepIds = tmp;  this.newDepIds.clear();  tmp = this.deps;  this.deps = this.newDeps;  this.newDeps = tmp;  this.newDeps.length = 0;};

cleanupDeps方法,清除依赖。

Watcher.prototype.update = function update () {  /* istanbul ignore else */  if (this.lazy) {    this.dirty = true;  } else if (this.sync) {    this.run();  } else {    queueWatcher(this);  }};

update方法,更新所观察的属性。

Watcher.prototype.run = function run () {  if (this.active) {    var value = this.get();    if (      value !== this.value ||      // Deep watchers and watchers on Object/Arrays should fire even      // when the value is the same, because the value may      // have mutated.      isObject(value) ||      this.deep    ) {      // set new value      var oldValue = this.value;      this.value = value;      if (this.user) {        try {          this.cb.call(this.vm, value, oldValue);        } catch (e) {          handleError(e, this.vm, ("callback for watcher \"" + (this.expression) + "\""));        }      } else {        this.cb.call(this.vm, value, oldValue);      }    }  }};

run方法,执行watcher实例所传的回调方法。

Watcher.prototype.evaluate = function evaluate () {  this.value = this.get();  this.dirty = false;};

重新获取watcher内的value值。目前不是很理解。

Watcher.prototype.depend = function depend () {    var this$1 = this;  var i = this.deps.length;  while (i--) {    this$1.deps[i].depend();  }};

为watcher内的每个dep添加依赖。

Watcher.prototype.teardown = function teardown () {    var this$1 = this;  if (this.active) {    // remove self from vm's watcher list    // this is a somewhat expensive operation so we skip it    // if the vm is being destroyed.    if (!this.vm._isBeingDestroyed) {      remove(this.vm._watchers, this);    }    var i = this.deps.length;    while (i--) {      this$1.deps[i].removeSub(this$1);    }    this.active = false;  }};

移除watcher自身所绑定的依赖。

原创粉丝点击