理解javascript中的MVC模式
MVC模式是軟件工程中一種軟件架構(gòu)模式,一般把軟件模式分為三部分,模型(Model)+視圖(View)+控制器(Controller);
模型:模型用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對(duì)數(shù)據(jù)處理的方法。模型有對(duì)數(shù)據(jù)直接訪問(wèn)的權(quán)利。模型不依賴 “視圖” 和 “控制器”, 也就是說(shuō) 模型它不關(guān)心頁(yè)面如何顯示及如何被操作.
視圖:視圖層最主要的是監(jiān)聽模型層上的數(shù)據(jù)改變,并且實(shí)時(shí)的更新html頁(yè)面。當(dāng)然也包括一些事件的注冊(cè)或者ajax請(qǐng)求操作(發(fā)布事件),都是放在視圖層來(lái)完成。
控制器:控制器接收用戶的操作,最主要是訂閱視圖層的事件,然后調(diào)用模型或視圖去完成用戶的操作;比如:當(dāng)頁(yè)面上觸發(fā)一個(gè)事件,控制器不輸出任何東西及對(duì)頁(yè)面做任何處理; 它只是接收請(qǐng)求并決定調(diào)用模型中的那個(gè)方法去處理請(qǐng)求, 然后再確定調(diào)用那個(gè)視圖中的方法來(lái)顯示返回的數(shù)據(jù)。
下面我們來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的下拉框控件,我們可以對(duì)它進(jìn)行增刪操作;如下圖所示:
代碼如下:
/* 模型用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對(duì)數(shù)據(jù)處理的方法。模型有對(duì)數(shù)據(jù)直接訪問(wèn)的權(quán)利。 模型不依賴 "視圖" 和 "控制器", 也就是說(shuō) 模型它不關(guān)心頁(yè)面如何顯示及如何被操作. */ function Mode(elems) { // 所有元素 this._elems = elems; // 被選中元素的索引 this._selectedIndex = -1; // 增加一項(xiàng) this.itemAdd = new Event(this); // 刪除一項(xiàng) this.itemRemoved = new Event(this); this.selectedIndexChanged = new Event(this); } Mode.prototype = { constructor: 'Mode', // 獲取所有的項(xiàng) getItems: function(){ return [].concat(this._elems); }, // 增加一項(xiàng) addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); }, // 刪除一項(xiàng) 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ā)布---訂閱模式;它定義了對(duì)象間的一種一對(duì)多的關(guān)系, 讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知。 */ 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ù) 負(fù)責(zé)轉(zhuǎn)發(fā)請(qǐng)求,對(duì)請(qǐng)求進(jìn)行處理 */ 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>
頁(yè)面初始化代碼如下:
$(function () { var model = new Mode(['PHP', 'JavaScript']), view = new View(model, { 'list' : $('#list'), 'addButton' : $('#plusBtn'), 'delButton' : $('#minusBtn') }), controller = new Controller(model, view); view.show(); });
代碼分析如下:
先分析下我們是要實(shí)現(xiàn)什么樣的功能,基本功能有:
一個(gè)下拉框,通過(guò)用戶輸入的操作來(lái)實(shí)現(xiàn)用戶增加一項(xiàng)及用戶選中一項(xiàng)后刪除一項(xiàng)的功能;
當(dāng)然也添加了用戶切換到那一項(xiàng)的事件;
比如我們現(xiàn)在來(lái)增加一條數(shù)據(jù)的時(shí)候,在視圖層上添加監(jiān)聽事件,如下代碼:
// 添加按鈕綁定事件 this._elements.addButton.click(function(e){ that.addButtonClicked.notify(); });
然后調(diào)用觀察者類Event中的方法notify(發(fā)布一個(gè)事件) that.addButtonClicked.notify();大家都知道,觀察者模式又叫發(fā)布-訂閱模式,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)某一個(gè)主題對(duì)象發(fā)生改變的時(shí)候,所有依賴它的對(duì)象都會(huì)得到通知;
因此在控制層(Controller)我們可以使用如下代碼對(duì)發(fā)布者進(jìn)行監(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()方法代碼如下:
// 增加一項(xiàng) addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); },
如上代碼 增加一項(xiàng)后,通過(guò) this.itemAdd 發(fā)布一個(gè)消息,然后在視圖層(View)上通過(guò)如下代碼來(lái)監(jiān)聽這個(gè)消息;代碼如下:
// 綁定模型監(jiān)聽器 this._model.itemAdd.attach(function(){ that.rebuildList(); });
最后監(jiān)聽到模型上(Model)的數(shù)據(jù)發(fā)生改變后,及時(shí)調(diào)用自身的方法rebuildList()去更新頁(yè)面上的數(shù)據(jù);
模型層(Model)最主要做業(yè)務(wù)數(shù)據(jù)封裝操作。視圖層(View)主要發(fā)布事件操作及監(jiān)聽模型層上的數(shù)據(jù),如果模型層上有數(shù)據(jù)改變的時(shí)候,及時(shí)更新頁(yè)面操作,最后顯示給頁(yè)面上來(lái),控制層(Controller)主要監(jiān)聽視圖層(View)的事件,調(diào)用模型層(Model)的方法來(lái)更新模型上的數(shù)據(jù),模型層數(shù)據(jù)更新后,會(huì)發(fā)布一條消息出去,最后視圖層(View)通過(guò)監(jiān)聽模型層(Model)的數(shù)據(jù)變化,來(lái)更新頁(yè)面的顯示; 如上是MVC的基本流程。
MVC的優(yōu)點(diǎn):
1. 耦合性低:視圖層和業(yè)務(wù)層分離了,如果頁(yè)面上顯示改變的話,直接在視圖層更改即可,不用動(dòng)模型層和控制層上的代碼;也就是視圖層 與 模型層和控制層
已經(jīng)分離了;所以很容易改變應(yīng)用層的數(shù)據(jù)層和業(yè)務(wù)規(guī)則。
2. 可維護(hù)性:分離視圖層和業(yè)務(wù)邏輯層也使得WEB應(yīng)用更易于維護(hù)和修改。
MVC的缺點(diǎn):
個(gè)人覺得適合于大型項(xiàng)目,對(duì)于中小型項(xiàng)目并不適合,因?yàn)橐獙?shí)現(xiàn)一個(gè)簡(jiǎn)單的增刪改操作,只需要一點(diǎn)點(diǎn)JS代碼,但是MVC模式代碼量明顯增加了。
對(duì)于學(xué)習(xí)成本也就提高了,當(dāng)然如果使用一些封裝好的MVC庫(kù)或者框架就好了。
以上就是關(guān)于javascript中的MVC模式實(shí)現(xiàn)方法,優(yōu)缺點(diǎn)的詳細(xì)分析,希望對(duì)大家的學(xué)習(xí)有所幫助。
相關(guān)文章
一個(gè)js封裝的不錯(cuò)的選項(xiàng)卡效果代碼
在論壇里經(jīng)常看到人問(wèn)選項(xiàng)卡或者類似選項(xiàng)卡的切換效果 這里封裝了個(gè)js,希望對(duì)大家有用 所有代碼都在下面了 如果有錯(cuò)誤或者建議,可以回貼告訴我,謝謝2008-02-02js實(shí)現(xiàn)遍歷含有input的table實(shí)例
這篇文章主要介紹了js實(shí)現(xiàn)遍歷含有input的table方法,結(jié)合實(shí)例形式分析了jsp讀取數(shù)據(jù)庫(kù)動(dòng)態(tài)生成table及JavaScript遍歷table的相關(guān)技巧,需要的朋友可以參考下2015-12-12微信小程序?qū)崿F(xiàn)文字從右向左無(wú)限滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)文字從右向左無(wú)限滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12javascript日期對(duì)象格式化為字符串的實(shí)現(xiàn)方法
本篇文章主要是對(duì)javascript日期對(duì)象格式化為字符串的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01

JS基于構(gòu)造函數(shù)實(shí)現(xiàn)的菜單滑動(dòng)顯隱效果【測(cè)試可用】

動(dòng)態(tài)加載js、css的實(shí)例代碼