MVC&MVVM

摘自 : https://juejin.im/post/593021272f301e0058273468

MVC

  • MVC是一種設(shè)計(jì)模式,它將應(yīng)用劃分為3個(gè)部分:數(shù)據(jù)(M模型)展示層(V視圖)用戶交互層V。結(jié)合一下下圖落萎,更能理解三者之間的關(guān)系炬灭。
MVC

一個(gè)事件的發(fā)生是這樣的過程

  • 用戶和應(yīng)用交互
  • 控制器的事件處理器被觸發(fā)
  • 控制器從模型中請(qǐng)求數(shù)據(jù)荣赶,并將其交給視圖
  • 視圖將數(shù)據(jù)呈現(xiàn)給用戶

模型:用來存放應(yīng)用的所有數(shù)據(jù)對(duì)象训唱。模型不必知曉視圖和控制器的細(xì)節(jié),模型只需包含數(shù)據(jù)及直接和這些數(shù)據(jù)相關(guān)的邏輯凿滤。任何事件處理代碼传泊、視圖模版,以及那些和模型無關(guān)的邏輯都應(yīng)當(dāng)隔離在模型之外

視圖:視圖層是呈現(xiàn)給用戶的鸭巴,用戶與之產(chǎn)生交互眷细。在javaScript應(yīng)用中,視圖大都是由html鹃祖、css和JavaScript模版組成的溪椎。除了模版中簡(jiǎn)單的條件語句之外,視圖不應(yīng)當(dāng)包含任何其他邏輯。事實(shí)上和模型類似校读,視圖也應(yīng)該從應(yīng)用的其他部分中解耦出來

控制器:控制器是模型和視圖的紐帶沼侣。控制器從視圖獲得事件和輸入歉秫,對(duì)它們進(jìn)行處理蛾洛,并相應(yīng)地更新視圖。當(dāng)頁面加載時(shí)雁芙,控制器會(huì)給視圖添加事件監(jiān)聽轧膘,比如監(jiān)聽表單提交和按鈕單擊。然后當(dāng)用戶和應(yīng)用產(chǎn)生交互時(shí)兔甘,控制器中的事件觸發(fā)器就開始工作谎碍。例如JavaScript框架早期框架backbone就是采用的MVC模式

Modal

MVC中M表示model,Model層用來存儲(chǔ)業(yè)務(wù)的數(shù)據(jù),一旦數(shù)據(jù)發(fā)生變化洞焙,模型將通知有關(guān)的視圖蟆淀。

myapp.Modal = function(){
  var val = 0
  this.add = (v) => { if(val < 100) val += v}
  this.sub = (v) => { if(val > 0) val -= v} 
  this.getVal = () => val
  
  //觀察者模式
  var self = this,
      views = [];
  
  this.register = view => {views.push(view)}
  this.notify = () => {
    for(var i = 0; i< views.length; i++){
      views[i].render(self)
    }
  }
}

Model和View之間使用了觀察者模式,View事先在此Model上注冊(cè)澡匪,進(jìn)而觀察Model熔任,以便更新在Model上發(fā)生改變的數(shù)據(jù)。

View

view和controller之間使用了策略模式唁情,這里View引入了Controller的實(shí)例來實(shí)現(xiàn)特定的響應(yīng)策略疑苔,比如這個(gè)栗子中按鈕的click事件:

myapp.View = function(controller) {
    var $num = $('#num'),
        $incBtn = $('#increase'),
        $decBtn = $('#decrease');

    this.render = function(model) {
        $num.text(model.getVal() + 'rmb');
    };

    /*  綁定事件  */
    $incBtn.click(controller.increase);
    $decBtn.click(controller.decrease);
};

Controller

控制器C是模型和視圖之間的紐帶,MVC將響應(yīng)機(jī)制封裝在controller對(duì)象中荠瘪,當(dāng)用戶和你的應(yīng)用產(chǎn)生交互時(shí),控制器中的事件觸發(fā)器就開始工作了赛惩。

myapp.Controller = function() {
    var model = null,
        view = null;

    this.init = function() {
        /* 初始化Model和View */
        model = new myapp.Model();
        view = new myapp.View(this);

        /* View向Model注冊(cè)哀墓,當(dāng)Model更新就會(huì)去通知View啦 */
        model.register(view);
        model.notify();
    };

    /* 讓Model更新數(shù)值并通知View更新視圖 */
    this.increase = function() {
        model.add(1);
        model.notify();
    };

    this.decrease = function() {
        model.sub(1);
        model.notify();
    };
}

實(shí)例化View并向?qū)?yīng)的Model實(shí)例注冊(cè),當(dāng)Model發(fā)生變化時(shí)就去通知View做更新喷兼,這里用到了觀察者模式篮绰。

當(dāng)我們執(zhí)行應(yīng)用的時(shí)候,使用Controller做初始化:

(function() {
    var controller = new myapp.Controller();
    controller.init();
})();

MVVM

MVVM(Model-View-ViewModel)最早由微軟提出季惯。ViewModel"Model of View"——視圖的模型吠各。

MVVM把View和Model的同步邏輯自動(dòng)化了。

來看一個(gè)Vue的例子:

Model

MVVM中勉抓,我們可以把Model稱為數(shù)據(jù)層贾漏,因?yàn)樗鼉H僅關(guān)注數(shù)據(jù)本身,不關(guān)心任何行為(格式化數(shù)據(jù)由View的負(fù)責(zé))藕筋,這里可以把它理解為一個(gè)類似json的數(shù)據(jù)對(duì)象纵散。

var data = {
 val : 0
}

View

MVC不同的是,MVVM中的View通過使用模板語法來聲明式的將數(shù)據(jù)渲染進(jìn)DOM,當(dāng)ViewModel對(duì)Model進(jìn)行更新的時(shí)候伍掀,會(huì)通過數(shù)據(jù)綁定更新到View掰茶。寫法如下:

<div id="myapp">
    <div>
        <span>{{ val }}rmb</span>
    </div>
    <div>
        <button v-on:click="sub(1)">-</button>
        <button v-on:click="add(1)">+</button>
    </div>
</div>

ViewModel

ViewModel大致上就是MVC的Controller和MVP的Presenter了,也是整個(gè)模式的重點(diǎn)蜜笤,業(yè)務(wù)邏輯也主要集中在這里濒蒋,其中的一大核心就是數(shù)據(jù)綁定,后面將會(huì)講到把兔。與MVP不同的是沪伙,沒有了View為Presente提供的接口,之前由Presenter負(fù)責(zé)的View和Model之間的數(shù)據(jù)同步交給了ViewModel中的數(shù)據(jù)綁定進(jìn)行處理垛贤,當(dāng)Model發(fā)生變化焰坪,ViewModel就會(huì)自動(dòng)更新;ViewModel變化聘惦,Model也會(huì)更新某饰。

new Vue({
    el: '#myapp',
    data: data,
    methods: {
        add(v) {
            if(this.val < 100) {
                this.val += v;
            }
        },
        sub(v) {
            if(this.val > 0) {
                this.val -= v;
            }
        }
    }
});

整體來看,比MVC精簡(jiǎn)了很多善绎,不僅僅簡(jiǎn)化了業(yè)務(wù)與界面的依賴黔漂,還解決了數(shù)據(jù)頻繁更新(以前用jQuery操作DOM很繁瑣)的問題。因?yàn)樵贛VVM中禀酱,View不知道Model的存在炬守,ViewModel和Model也察覺不到View,這種低耦合模式可以使開發(fā)過程更加容易剂跟,提高應(yīng)用的可重用性减途。

數(shù)據(jù)綁定

雙向數(shù)據(jù)綁定,可以簡(jiǎn)單而不恰當(dāng)?shù)乩斫鉃橐粋€(gè)模版引擎曹洽,但是會(huì)根據(jù)數(shù)據(jù)變更實(shí)時(shí)渲染鳍置。

雙向綁定

不同的MVVM框架中,實(shí)現(xiàn)雙向數(shù)據(jù)綁定的技術(shù)有所不同送淆。目前一些主流的前端框架實(shí)現(xiàn)數(shù)據(jù)綁定的方式大致有以下幾種:

  • 數(shù)據(jù)劫持 (Vue)
  • 發(fā)布-訂閱模式 (Knockout税产、Backbone)
  • 臟值檢查 (Angular)

Vue采用數(shù)據(jù)劫持&發(fā)布-訂閱模式的方式,通過ES5提供的 Object.defineProperty()方法來劫持(監(jiān)控)各屬性的 getter 偷崩、setter 辟拷,并在數(shù)據(jù)(對(duì)象)發(fā)生變動(dòng)時(shí)通知訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)阐斜。并且衫冻,由于是在不同的數(shù)據(jù)上觸發(fā)同步,可以精確的將變更發(fā)送給綁定的視圖谒出,而不是對(duì)所有的數(shù)據(jù)都執(zhí)行一次檢測(cè)羽杰。要實(shí)現(xiàn)Vue中的雙向數(shù)據(jù)綁定渡紫,大致可以劃分三個(gè)模塊:Observer、Compile考赛、Watcher惕澎,如圖:

image.png

  • Observer 數(shù)據(jù)監(jiān)聽器
    負(fù)責(zé)對(duì)數(shù)據(jù)對(duì)象的所有屬性進(jìn)行監(jiān)聽(數(shù)據(jù)劫持),監(jiān)聽到數(shù)據(jù)發(fā)生變化后通知訂閱者颜骤。
  • Compiler 指令解析器
    掃描模板唧喉,并對(duì)指令進(jìn)行解析,然后綁定指定事件忍抽。
  • Watcher 訂閱者
    關(guān)聯(lián)Observer和Compile八孝,能夠訂閱并收到屬性變動(dòng)的通知,執(zhí)行指令綁定的相應(yīng)操作鸠项,更新視圖干跛。Update()是它自身的一個(gè)方法,用于執(zhí)行Compile中綁定的回調(diào)祟绊,更新視圖楼入。

總結(jié)

MV*的目的是把應(yīng)用程序的數(shù)據(jù)、業(yè)務(wù)邏輯和界面這三塊解耦牧抽,分離關(guān)注點(diǎn)嘉熊,不僅利于團(tuán)隊(duì)協(xié)作和測(cè)試,更有利于甩鍋維護(hù)和管理扬舒。業(yè)務(wù)邏輯不再關(guān)心底層數(shù)據(jù)的讀寫阐肤,而這些數(shù)據(jù)又以對(duì)象的形式呈現(xiàn)給業(yè)務(wù)邏輯層。從 MVC --> MVP --> MVVM讲坎,就像一個(gè)打怪升級(jí)的過程孕惜,它們都是在MVC的基礎(chǔ)上隨著時(shí)代和應(yīng)用環(huán)境的發(fā)展衍變而來的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晨炕,一起剝皮案震驚了整個(gè)濱河市衫画,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌府瞄,老刑警劉巖碧磅,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碘箍,死亡現(xiàn)場(chǎng)離奇詭異遵馆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丰榴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門货邓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人四濒,你說我怎么就攤上這事换况≈氨妫” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵戈二,是天一觀的道長(zhǎng)舒裤。 經(jīng)常有香客問我,道長(zhǎng)觉吭,這世上最難降的妖魔是什么腾供? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮鲜滩,結(jié)果婚禮上伴鳖,老公的妹妹穿的比我還像新娘。我一直安慰自己徙硅,他們只是感情好榜聂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗓蘑,像睡著了一般须肆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脐往,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天休吠,我揣著相機(jī)與錄音,去河邊找鬼业簿。 笑死瘤礁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梅尤。 我是一名探鬼主播柜思,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼巷燥!你這毒婦竟也來了赡盘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤缰揪,失蹤者是張志新(化名)和其女友劉穎陨享,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钝腺,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抛姑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了艳狐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片定硝。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖毫目,靈堂內(nèi)的尸體忽然破棺而出蔬啡,到底是詐尸還是另有隱情诲侮,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布箱蟆,位于F島的核電站沟绪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏空猜。R本人自食惡果不足惜近零,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抄肖。 院中可真熱鬧久信,春花似錦、人聲如沸漓摩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管毙。三九已至腿椎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間夭咬,已是汗流浹背啃炸。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卓舵,地道東北人南用。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像掏湾,于是被迫代替她去往敵國(guó)和親裹虫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容