vue 函数配置项watch以及函数 $watch 源码分享
2018-11-22 08:42:41来源:博客园 阅读 ()
// 为data的的所有属性添加getter 和 setter
function defineReactive( obj,key,val,customSetter,shallow
) {
//
var dep = new Dep();
/*....省略部分....*/
var childOb = !shallow && observe(val); //为对象添加备份依赖dep
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend(); //
if (childOb) {
childOb.dep.depend(); //依赖dep 添加watcher 用于set ,array改变等使用
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter(newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if ("development" !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
dep.notify();//有改变触发watcher进行更新
}
});
}
Vue.prototype.$watch = function (
expOrFn,
cb,
options
) {
var vm = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {};
options.user = true;
//为需要观察的 expOrFn 添加watcher ,expOrFn的值有改变时执行cb,
//在watcher的实例化的过程中会对expOrFn进行解析,并为expOrFn涉及到的data数据下的def添加该watcher
var watcher = new Watcher(vm, expOrFn, cb, options);
//immediate==true 立即执行watch handler
if (options.immediate) {
cb.call(vm, watcher.value);
}
//取消观察函数
return function unwatchFn() {
watcher.teardown();
}
};
var Watcher = function Watcher(
vm,
expOrFn,
cb,
options,
isRenderWatcher
) {
this.vm = vm;
if (isRenderWatcher) {
vm._watcher = this;
}
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$1; // 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 {
// 将需要观察的数据:string | Function | Object | Array等进行解析 如:a.b.c, 并返回访问该表达式的函数
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.get()将访问需要观察的数据
this.value = this.lazy
? undefined
: this.get();
};
/**
* Evaluate the getter, and re-collect dependencies.
*/
Watcher.prototype.get = function get() {
//this为$watch方法中实例化的watcher
pushTarget(this);讲this赋给Dep.target并缓存之前的watcher
var value;
var vm = this.vm;
try {
//访问需要观察的数据,在获取数据的getter中执行dep.depend();将$watch方法中实例化的watcher添加到对应数据下的dep中
value = this.getter.call(vm, vm);
} catch (e) {
if (this.user) {
handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value);
}
popTarget(); //将之前的watcher赋给Dep.target
this.cleanupDeps();
}
return value
};
观察的对象改变时将执行该方法
Watcher.prototype.run = function run() { /*....省略部分....*/ var value = this.get(); //重新获取info的值 var oldValue = this.value; //保存老的值 this.value = value; this.cb.call(this.vm, value, oldValue); //执行watch的回调 /*....省略部分....*/ };
以上代码在watcher实例化的时候执行 this.getter = parsePath(expOrFn); 返回一个访问该属性的函数,参数为被访问的对象 如vm.$watch("info",function(new, old){console.log("watch success")});, this.getter =function(obj){return obj.info};,在执行watcher的get方法中,将执行value = this.getter.call(vm, vm);,触发属性的get方法,添加该watcher至info属性对应的def对象中,如果需要深度监听,将执行traverse(value),依次访问info(假设info只对象)对象下的属性,如果info的属性还有是对象的属性,将进行递归访问,以达到info以及info下所有的属性的def对象都会添加该watcher实例。
当我们执行vm.info="change"时,将出发info的set方法,执行dep.notify();出发info所依赖的watcher执行watcher的run方法,即实现监听
举例
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:VUE的指令
- JavaScript函数表达式详解及实例 2020-03-25
- vue.js开发环境搭建教程 2020-03-16
- 带你了解JavaScript中的函数 2020-03-08
- Vue input控件通过value绑定动态属性及修饰符的方法 2020-03-05
- 详解Webstorm 新建.vue文件支持高亮vue语法和es6语法 2020-02-07
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash
