理解javascript中的MVC模式
MVC模式是軟件工程中一種軟件架構(gòu)模式,一般把軟件模式分為三部分,模型(Model)+視圖(View)+控制器(Controller);
模型:模型用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對數(shù)據(jù)處理的方法。模型有對數(shù)據(jù)直接訪問的權(quán)利。模型不依賴 “視圖” 和 “控制器”, 也就是說 模型它不關(guān)心頁面如何顯示及如何被操作.
視圖:視圖層最主要的是監(jiān)聽模型層上的數(shù)據(jù)改變,并且實時的更新html頁面。當然也包括一些事件的注冊或者ajax請求操作(發(fā)布事件),都是放在視圖層來完成。
控制器:控制器接收用戶的操作,最主要是訂閱視圖層的事件,然后調(diào)用模型或視圖去完成用戶的操作;比如:當頁面上觸發(fā)一個事件,控制器不輸出任何東西及對頁面做任何處理; 它只是接收請求并決定調(diào)用模型中的那個方法去處理請求, 然后再確定調(diào)用那個視圖中的方法來顯示返回的數(shù)據(jù)。
下面我們來實現(xiàn)一個簡單的下拉框控件,我們可以對它進行增刪操作;如下圖所示:
代碼如下:
/* 模型用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對數(shù)據(jù)處理的方法。模型有對數(shù)據(jù)直接訪問的權(quán)利。 模型不依賴 "視圖" 和 "控制器", 也就是說 模型它不關(guān)心頁面如何顯示及如何被操作. */ function Mode(elems) { // 所有元素 this._elems = elems; // 被選中元素的索引 this._selectedIndex = -1; // 增加一項 this.itemAdd = new Event(this); // 刪除一項 this.itemRemoved = new Event(this); this.selectedIndexChanged = new Event(this); } Mode.prototype = { constructor: 'Mode', // 獲取所有的項 getItems: function(){ return [].concat(this._elems); }, // 增加一項 addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); }, // 刪除一項 removeItem: function(index) { var item = this._elems[index]; this._elems.splice(index,1); this.itemRemoved.notify({elem:item}); if(index === this._selectedIndex) { this.setSelectedIndex(-1); } }, getSelectedIndex: function(){ return this._selectedIndex; }, setSelectedIndex: function(index){ var previousIndex = this._selectedIndex; this._selectedIndex = index; this.selectedIndexChanged.notify({previous : previousIndex}); } }; /* 下面是觀察者模式類,它又叫發(fā)布---訂閱模式;它定義了對象間的一種一對多的關(guān)系, 讓多個觀察者對象同時監(jiān)聽某一個主題對象,當一個對象發(fā)生改變時,所有依賴于它的對象都將得到通知。 */ function Event(observer) { this._observer = observer; this._listeners = []; } Event.prototype = { constaructor: 'Event', attach : function(listeners) { this._listeners.push(listeners); }, notify: function(objs){ for(var i = 0,ilen = this._listeners.length; i ) { this._listeners[i](this._observer,objs); } } }; /* * 視圖顯示模型數(shù)據(jù),并觸發(fā)UI事件。 */ function View(model,elements){ this._model = model; this._elements = elements; this.listModified = new Event(this); this.addButtonClicked = new Event(this); this.delButtonClicked = new Event(this); var that = this; // 綁定模型監(jiān)聽器 this._model.itemAdd.attach(function(){ that.rebuildList(); }); this._model.itemRemoved.attach(function(){ that.rebuildList(); }); // 將監(jiān)聽器綁定到HTML控件上 this._elements.list.change(function(e){ that.listModified.notify({index: e.target.selectedIndex}); }); // 添加按鈕綁定事件 this._elements.addButton.click(function(e){ that.addButtonClicked.notify(); }); // 刪除按鈕綁定事件 this._elements.delButton.click(function(e){ that.delButtonClicked.notify(); }); } View.prototype = { constructor: 'View', show: function(){ this.rebuildList(); }, rebuildList: function(){ var list = this._elements.list, items, key; list.html(""); items = this._model.getItems(); for(key in items) { if(items.hasOwnProperty(key)) { list.append('' +items[key]+ ''); } } this._model.setSelectedIndex(-1); } }; /* 控制器響應(yīng)用戶操作,調(diào)用模型上的變化函數(shù) 負責(zé)轉(zhuǎn)發(fā)請求,對請求進行處理 */ function Controller(model,view) { this._model = model; this._view = view; var that = this; this._view.listModified.attach(function(sender,args){ that.updateSelected(args.index); }); this._view.addButtonClicked.attach(function(){ that.addItem(); }); this._view.delButtonClicked.attach(function(){ that.delItem(); }); } Controller.prototype = { constructor: 'Controller', addItem: function(){ var item = window.prompt('Add item:', ''); if (item) { this._model.addItem(item); } }, delItem: function(){ var index = this._model.getSelectedIndex(); if(index !== -1) { this._model.removeItem(index); } }, updateSelected: function(index){ this._model.setSelectedIndex(index); } };
HTML代碼如下:
<select id="list" size="10" style="width: 10rem">select>br/> <button id="plusBtn"> + button> <button id="minusBtn"> - button>
頁面初始化代碼如下:
$(function () { var model = new Mode(['PHP', 'JavaScript']), view = new View(model, { 'list' : $('#list'), 'addButton' : $('#plusBtn'), 'delButton' : $('#minusBtn') }), controller = new Controller(model, view); view.show(); });
代碼分析如下:
先分析下我們是要實現(xiàn)什么樣的功能,基本功能有:
一個下拉框,通過用戶輸入的操作來實現(xiàn)用戶增加一項及用戶選中一項后刪除一項的功能;
當然也添加了用戶切換到那一項的事件;
比如我們現(xiàn)在來增加一條數(shù)據(jù)的時候,在視圖層上添加監(jiān)聽事件,如下代碼:
// 添加按鈕綁定事件 this._elements.addButton.click(function(e){ that.addButtonClicked.notify(); });
然后調(diào)用觀察者類Event中的方法notify(發(fā)布一個事件) that.addButtonClicked.notify();大家都知道,觀察者模式又叫發(fā)布-訂閱模式,讓多個觀察者對象同時監(jiān)聽某一個主題對象,當某一個主題對象發(fā)生改變的時候,所有依賴它的對象都會得到通知;
因此在控制層(Controller)我們可以使用如下代碼對發(fā)布者進行監(jiān)聽操作:
this._view.addButtonClicked.attach(function(){ that.addItem(); });
之后調(diào)用自身的方法addItem();代碼如下:
addItem: function(){ var item = window.prompt('Add item:', ''); if (item) { this._model.addItem(item); } }
調(diào)用模型層(model)的方法addItem();把一條數(shù)據(jù)插入到select框里面去;model(模型層)的addItem()方法代碼如下:
// 增加一項 addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); },
如上代碼 增加一項后,通過 this.itemAdd 發(fā)布一個消息,然后在視圖層(View)上通過如下代碼來監(jiān)聽這個消息;代碼如下:
// 綁定模型監(jiān)聽器 this._model.itemAdd.attach(function(){ that.rebuildList(); });
最后監(jiān)聽到模型上(Model)的數(shù)據(jù)發(fā)生改變后,及時調(diào)用自身的方法rebuildList()去更新頁面上的數(shù)據(jù);
模型層(Model)最主要做業(yè)務(wù)數(shù)據(jù)封裝操作。視圖層(View)主要發(fā)布事件操作及監(jiān)聽模型層上的數(shù)據(jù),如果模型層上有數(shù)據(jù)改變的時候,及時更新頁面操作,最后顯示給頁面上來,控制層(Controller)主要監(jiān)聽視圖層(View)的事件,調(diào)用模型層(Model)的方法來更新模型上的數(shù)據(jù),模型層數(shù)據(jù)更新后,會發(fā)布一條消息出去,最后視圖層(View)通過監(jiān)聽模型層(Model)的數(shù)據(jù)變化,來更新頁面的顯示; 如上是MVC的基本流程。
MVC的優(yōu)點:
1. 耦合性低:視圖層和業(yè)務(wù)層分離了,如果頁面上顯示改變的話,直接在視圖層更改即可,不用動模型層和控制層上的代碼;也就是視圖層 與 模型層和控制層
已經(jīng)分離了;所以很容易改變應(yīng)用層的數(shù)據(jù)層和業(yè)務(wù)規(guī)則。
2. 可維護性:分離視圖層和業(yè)務(wù)邏輯層也使得WEB應(yīng)用更易于維護和修改。
MVC的缺點:
個人覺得適合于大型項目,對于中小型項目并不適合,因為要實現(xiàn)一個簡單的增刪改操作,只需要一點點JS代碼,但是MVC模式代碼量明顯增加了。
對于學(xué)習(xí)成本也就提高了,當然如果使用一些封裝好的MVC庫或者框架就好了。
以上就是關(guān)于javascript中的MVC模式實現(xiàn)方法,優(yōu)缺點的詳細分析,希望對大家的學(xué)習(xí)有所幫助。
相關(guān)文章
javascript日期對象格式化為字符串的實現(xiàn)方法
本篇文章主要是對javascript日期對象格式化為字符串的實現(xiàn)方法進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01JS基于構(gòu)造函數(shù)實現(xiàn)的菜單滑動顯隱效果【測試可用】
這篇文章主要介紹了JS基于構(gòu)造函數(shù)實現(xiàn)的菜單滑動顯隱效果,可實現(xiàn)基本的菜單折疊與展開功能,涉及javascript響應(yīng)鼠標事件動態(tài)操作頁面元素的相關(guān)技巧,需要的朋友可以參考下2016-06-06