摘要:在此種模式中,一個(gè)目標(biāo)對象管理所有相依于它的觀察者對象,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。訂閱者模式涉及三個(gè)對象發(fā)布者主題對象訂閱者,三個(gè)對象間的是一對多的關(guān)系,每當(dāng)主題對象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴對象都會(huì)得到通知,并被自動(dòng)更新。
1./compiler ?目錄是編譯模版;
2./core ?目錄是 Vue.js 的核?心(也是后?面的重點(diǎn));
3./platforms ?目錄是針對核?心模塊的 ‘平臺(tái)’ 模塊;
4./server ?目錄是處理理服務(wù)端渲染;
5./sfc ?目錄處理理單?文件 .vue;
6./shared ?目錄提供全局?用到的?工具函數(shù)。
Vue.js 的組成是由 core + 對應(yīng)的 ‘平臺(tái)’ 補(bǔ)充代碼構(gòu)成(獨(dú)立構(gòu)建和運(yùn)行時(shí)構(gòu)建 只是 platforms 下 web 平臺(tái)的兩種選擇)。
雙向綁定(響應(yīng)式原理)所涉及到的技術(shù)
1. Object.defineProperty 2. Observer 3. Watcher 4. Dep 5. Directive1. Object.defineProperty
var obj = {};
var a;
Object.defineProperty(obj,"a",{
get: function(){
console.log("get val");
return a;
},
set: function(newVal){
console.log("set val:" + newVal);
a = newVal;
}
});
obj.a // get val; 相當(dāng)于{{a}}
obj.a = "111"; // set val:111 相當(dāng)于
setter 觸發(fā)消息到 Watcher watcher幫忙告訴 Directive 更新DOM,DOM中修改了數(shù)據(jù) 也會(huì)通知給 Watcher,watcher 幫忙修改數(shù)據(jù)。
觀察者模式是軟件設(shè)計(jì)模式的一種。 在此種模式中,一個(gè)目標(biāo)對象管理所有相依于它的觀 察者對象,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。 這通常透過呼叫各觀察者所提供的 方法來實(shí)現(xiàn)。此種模式通常被用來實(shí)時(shí)事件處理系統(tǒng)。 訂閱者模式涉及三個(gè)對象: 發(fā)布者、主題對象、訂閱者,三個(gè)對象間的是一對多的關(guān)系, 每當(dāng)主題對象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴對象都會(huì)得到通知,并被自動(dòng)更新。 看一個(gè)簡單的示例:
vue里邊怎么操作的呢? vue observer
watcher
Dep
Directive
弄明白原理和架構(gòu)之后,我們來實(shí)現(xiàn)一個(gè)簡單的vue雙向數(shù)據(jù)綁定
1.這個(gè)Vue是從哪里來的呢?
是通過上述方法實(shí)例化的一個(gè)對象;但是里邊有兩個(gè)未知生物 observe ? Compile?
observe中寫的是雙向綁定的核心原理就是Object.defineProperty
通過set,get來設(shè)置值與獲取值
把text屬性綁定到vue實(shí)例上面去使用
那其中的Dep又是什么呢?
添加訂閱者跟通知訂閱更新
再來看一下Compile中寫的什么吧
function Compile(node, vm) { if (node) { this.$frag = this.nodeToFragment(node, vm); return this.$frag; } } Compile.prototype = { nodeToFragment: function (node, vm) { var self = this; var frag = document.createDocumentFragment(); // 創(chuàng)建一段html文檔片段 var child; while (child = node.firstChild) { self.compileElement(child, vm); frag.append(child); // 將所有子節(jié)點(diǎn)添加到fragment中 } return frag; }, compileElement: function (node, vm) { var reg = /{{(.*)}}/; //節(jié)點(diǎn)類型為元素 if (node.nodeType === 1) { var attr = node.attributes; // 解析屬性 for (var i = 0; i < attr.length; i++) { if (attr[i].nodeName == "v-model") { var name = attr[i].nodeValue; // 獲取v-model綁定的屬性名 node.addEventListener("input", function (e) { // 給相應(yīng)的data屬性賦值,進(jìn)而觸發(fā)該屬性的set方法 // 觸發(fā)set vm[name] vm[name] = e.target.value; }); // node.value = vm[name]; // 將data的值賦給該node new Watcher(vm, node, name, "value"); } }; } //節(jié)點(diǎn)類型為text if (node.nodeType === 3) { if (reg.test(node.nodeValue)) { var name = RegExp.$1; // 獲取匹配到的字符串 name = name.trim(); // node.nodeValue = vm[name]; // 將data的值賦給該node new Watcher(vm, node, name, "nodeValue"); } } }, }
哦,原來Compile中是渲染html的啊。其中的Watcher是不是監(jiān)控節(jié)點(diǎn)變化,然后給Dep通知的呢?
function Watcher(vm, node, name, type) { Dep.target = this; this.name = name; //text this.node = node; // 節(jié)點(diǎn) this.vm = vm; // vue實(shí)例 this.type = type; //nodeValue 當(dāng)前節(jié)點(diǎn)的值 this.update(); Dep.target = null; } Watcher.prototype = { update: function() { this.get(); var batcher = new Batcher(); batcher.push(this); // this.node[this.type] = this.value; // 訂閱者執(zhí)行相應(yīng)操作 }, cb:function(){ this.node[this.type] = this.value; // 訂閱者執(zhí)行相應(yīng)操作 }, // 獲取data的屬性值 get: function() { this.value = this.vm[this.name]; //觸發(fā)相應(yīng)屬性的get } }
哎呦,咱們猜對了呢,這樣雙向數(shù)據(jù)綁定馬上就要完成了,只剩一個(gè)Vue.nextTick()的地方了
/** * 批處理構(gòu)造函數(shù) * @constructor */ function Batcher() { this.reset(); } /** * 批處理重置 */ Batcher.prototype.reset = function () { this.has = {}; this.queue = []; this.waiting = false; }; /** * 將事件添加到隊(duì)列中 * @param job {Watcher} watcher事件 */ Batcher.prototype.push = function (job) { if (!this.has[job.name]) { this.queue.push(job); this.has[job.name] = job; if (!this.waiting) { this.waiting = true; setTimeout(() => { this.flush(); }); } } }; /** * 執(zhí)行并清空事件隊(duì)列 */ Batcher.prototype.flush = function () { this.queue.forEach((job) => { job.cb(); }); this.reset(); };
看完后是不是覺得超簡單呢?
vue3版本將做出巨大的變化,把Dep跟Watcher都干掉了,html直接跟數(shù)據(jù)進(jìn)行綁定,等vue3出來后,在寫一篇關(guān)于vue的文章吧
看完后能幫我點(diǎn)個(gè)贊嗎?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/108851.html
摘要:學(xué)完的基礎(chǔ)語法之后,練手一下,從最基本的留言板開刀吧。功能不多,主要為了熟悉的基礎(chǔ)語法使用。 學(xué)完vue的基礎(chǔ)語法之后,練手一下,從最基本的留言板開刀吧。功能不多,主要為了熟悉vue的基礎(chǔ)語法使用。詳細(xì)vue教程請移步vue.js 2.0 技術(shù)框架 1.vue.js 2.0 2.bootstrap 語法概述 這里只寫一點(diǎn)此例子用到的一些語法知識,詳細(xì)API請移步:vue 2.0 a...
摘要:實(shí)現(xiàn)的一套博客系統(tǒng)包括博客前端展示頁和博客后臺(tái)管理頁貌似預(yù)覽圖加載不出來,直接點(diǎn)看吧項(xiàng)目地址簡要技術(shù)棧后臺(tái)管理頁的編輯器用的,支持語法解析部分使用了這個(gè)庫,語法高亮用博客在線地址僅供臨時(shí)預(yù)覽博客后臺(tái)管理頁在線地址僅供臨時(shí)預(yù)覽博客后臺(tái)管理 vue+node 實(shí)現(xiàn)的一套博客系統(tǒng),包括博客前端展示頁和博客后臺(tái)管理頁 segmentfault貌似預(yù)覽圖加載不出來,直接點(diǎn)?github看吧 項(xiàng)目...
摘要:由于眾所周知的原因,谷歌字體只能過墻后才能被正常加載,而中的原生使用了谷歌字體,在這個(gè)案例中改為使用。代碼存在,國內(nèi)訪問速度沒那么快,初次加載較慢請耐心等待。如果項(xiàng)目對你有所幫助,不妨一下,你的支持是我前進(jìn)的最大動(dòng)力。 效果圖: showImg(https://segmentfault.com/img/remote/1460000008172654?w=303&h=545); show...
閱讀 1216·2021-10-09 09:43
閱讀 19177·2021-09-22 15:52
閱讀 1163·2019-08-30 15:44
閱讀 3121·2019-08-30 15:44
閱讀 3308·2019-08-26 14:07
閱讀 967·2019-08-26 13:55
閱讀 2632·2019-08-26 13:41
閱讀 3167·2019-08-26 13:29