您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“vue中函數(shù)配置項(xiàng)watch及函數(shù)$watch的示例分析”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“vue中函數(shù)配置項(xiàng)watch及函數(shù)$watch的示例分析”這篇文章吧。
Vue雙向榜單的原理
大家都知道Vue采用的是MVVM的設(shè)計(jì)模式,采用數(shù)據(jù)驅(qū)動(dòng)實(shí)現(xiàn)雙向綁定,不明白雙向綁定原理的需要先補(bǔ)充雙向綁定的知識(shí),在watch的處理中將運(yùn)用到Vue的雙向榜單原理,所以再次回顧一下:
Vue的數(shù)據(jù)通過(guò)Object.defineProperty
設(shè)置對(duì)象的get和set實(shí)現(xiàn)對(duì)象屬性的獲取,vue的data下的數(shù)據(jù)對(duì)應(yīng)唯一 一個(gè)dep對(duì)象,dep對(duì)象會(huì)存儲(chǔ)改屬性對(duì)應(yīng)的watcher,在獲取數(shù)據(jù)(get)的時(shí)候?yàn)橄嚓P(guān)屬性添加具有對(duì)應(yīng)處理函數(shù)的watcher,在設(shè)置屬性的時(shí)候,觸發(fā)def對(duì)象下watcher執(zhí)行相關(guān)的邏輯
// 為data的的所有屬性添加getter 和 setter function defineReactive( obj,key,val,customSetter,shallow ) { // var dep = new Dep(); /*....省略部分....*/ var childOb = !shallow && observe(val); //為對(duì)象添加備份依賴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();//有改變觸發(fā)watcher進(jìn)行更新 } }); }
在vue進(jìn)行實(shí)例化的時(shí)候,將調(diào)用 initWatch(vm, opts.watch);進(jìn)行初始化watch的初始化,該函數(shù)最終將調(diào)用 vm.$watch
(expOrFn, handler, options) 進(jìn)行watch的配置,下面我們將講解 vm.$watch方法
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的值有改變時(shí)執(zhí)行cb, //在watcher的實(shí)例化的過(guò)程中會(huì)對(duì)expOrFn進(jìn)行解析,并為expOrFn涉及到的data數(shù)據(jù)下的def添加該watcher var watcher = new Watcher(vm, expOrFn, cb, options); //immediate==true 立即執(zhí)行watch handler if (options.immediate) { cb.call(vm, watcher.value); } //取消觀察函數(shù) return function unwatchFn() { watcher.teardown(); } };
來(lái)看看實(shí)例化watcher的過(guò)程中(只分享是觀察函數(shù)中的實(shí)例的watcher)
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; //是否觀察對(duì)象內(nèi)部值的變化 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; // 觀察屬性改變時(shí)執(zhí)行的函數(shù) 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 { // 將需要觀察的數(shù)據(jù):string | Function | Object | Array等進(jìn)行解析 如:a.b.c, 并返回訪問(wèn)該表達(dá)式的函數(shù) 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()將訪問(wèn)需要觀察的數(shù)據(jù) this.value = this.lazy ? undefined : this.get(); }; /** * Evaluate the getter, and re-collect dependencies. */ Watcher.prototype.get = function get() { //this為$watch方法中實(shí)例化的watcher pushTarget(this);講this賦給Dep.target并緩存之前的watcher var value; var vm = this.vm; try { //訪問(wèn)需要觀察的數(shù)據(jù),在獲取數(shù)據(jù)的getter中執(zhí)行dep.depend();將$watch方法中實(shí)例化的watcher添加到對(duì)應(yīng)數(shù)據(jù)下的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 };<br><br><br><br> Watcher.prototype.run = function run() { /*....省略部分....*/ var value = this.get(); //重新獲取info的值 var oldValue = this.value; //保存老的值 this.value = value; this.cb.call(this.vm, value, oldValue); //執(zhí)行watch的回調(diào) /*....省略部分....*/ };
以上代碼在watcher實(shí)例化的時(shí)候執(zhí)行 this.getter = parsePath(expOrFn);
返回一個(gè)訪問(wèn)該屬性的函數(shù),參數(shù)為被訪問(wèn)的對(duì)象 如vm.$watch("info",function(new, old){console.log("watch success")});, this.getter =function(obj){return obj.info};,
在執(zhí)行watcher的get方法中,將執(zhí)行value = this.getter.call(vm, vm);,觸發(fā)屬性的get方法,添加該watcher至info屬性對(duì)應(yīng)的def對(duì)象中,如果需要深度監(jiān)聽(tīng),將執(zhí)行traverse(value),依次訪問(wèn)info(假設(shè)info只對(duì)象)對(duì)象下的屬性,如果info的屬性還有是對(duì)象的屬性,將進(jìn)行遞歸訪問(wèn),以達(dá)到info以及info下所有的屬性的def對(duì)象都會(huì)添加該watcher實(shí)例。
當(dāng)我們執(zhí)行vm.info="change"
時(shí),將出發(fā)info的set方法,執(zhí)行dep.notify();
出發(fā)info所依賴的watcher執(zhí)行watcher的run方法,即實(shí)現(xiàn)監(jiān)聽(tīng)
以上是“vue中函數(shù)配置項(xiàng)watch及函數(shù)$watch的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。