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自身所绑定的依赖。
阅读全文
0 0
- Vue源码解析(二)
- Vue源码解析(一)
- Vue源码解析(三)
- Vue源码解析(四)
- Vue源码解析(五)
- 自己实现MVVM(Vue源码解析)
- vue源码解析
- jrae源码解析(二)
- jrae源码解析(二)
- HDFS源码解析(二)
- OKHttp源码解析(二)
- OKHttp源码解析(二)
- OKHttp源码解析(二)
- AsyncTask源码解析(二)
- SDWebImage源码解析(二)
- BroadcastReceiver源码解析(二)
- Volley 源码解析(二)
- OKHttp源码解析(二)
- 【C#】委托和事件
- Java并发之AQS详解
- 9.2【某二十四中数据真水】
- jpa_jpql笔记最终版
- 2017.8.30
- Vue源码解析(二)
- 洛谷1144 最短路记数 bfs
- leetcode 113 pathSum2
- 前端之框架-bootstrap
- angular Js 学习笔记(一)
- JavaScript选择文本方法
- 2017.8.31
- GO 左右移用法
- 字符串模式匹配(KMP)