日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
前端MVC變形記

背景:

MVC是一種架構(gòu)設(shè)計模式,它通過關(guān)注點分離鼓勵改進應(yīng)用程序組織。在過去,MVC被大量用于構(gòu)建桌面和服務(wù)器端應(yīng)用程序,如今Web應(yīng)用程序的開發(fā)已經(jīng)越來越向傳統(tǒng)應(yīng)用軟件開發(fā)靠攏,Web和應(yīng)用之間的界限也進一步模糊。傳統(tǒng)編程語言中的設(shè)計模式也在慢慢地融入Web前端開發(fā)。由于前端開發(fā)的環(huán)境特性,在經(jīng)典MVC模式上也引申出了諸多MV*模式,被實現(xiàn)到各個Javascript框架中都有多少的衍變。在研究MV*模式和各框架的過程中,卻是“剪不斷、理還亂”:

  1. 為什么每個地方講的MVC都不太一樣?
  2. MVP、MVVM的出現(xiàn)是要解決什么問題?
  3. 為什么有人義正言辭的說“MVC在Web前端開發(fā)中根本無法使用”?

帶著十萬個為什么去翻閱很多資料,但是看起來像view、model、controller、解耦、監(jiān)聽、通知、主動、被動、注冊、綁定、渲染等各種術(shù)語的排列組合,像汪峰的歌詞似的。本篇希望用通俗易懂的方式闡述清楚一些關(guān)系,由于接觸時間有限,英文閱讀能力有限,可能會存在誤解,歡迎討論和糾正。

MVC變形記

MVC歷史

MVC最初是在研究Smalltalk-80(1979年)期間設(shè)計出來的,恐怕沒有一本書能夠回到計算機石器時代介紹一下Smalltalk的代碼是如何實現(xiàn)MVC的,不僅如此,連想搞清楚當(dāng)時的應(yīng)用場景都很難了,都要追溯到80后出生以前的事了。但是當(dāng)時的圖形界面少之又少,施樂公司正在研發(fā)友好的用戶圖形界面,以取代電腦屏幕上那些拒人于千里之外的命令行和DOS提示符。那時計算機世界天地混沌,渾然一體,然后出現(xiàn)了一個創(chuàng)世者,將現(xiàn)實世界抽象出模型形成model,將人機交互從應(yīng)用邏輯中分離形成view,然后就有了空氣、水、雞啊、蛋什么的。在1995年出版的《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》對MVC進行了深入的闡述,在推廣使用方面發(fā)揮了重要作用。

MVC包括三類對象,將他們分離以提高靈活性和復(fù)用性。

  • 模型model用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對數(shù)據(jù)的處理方法,會有一個或多個視圖監(jiān)聽此模型。一旦模型的數(shù)據(jù)發(fā)生變化,模型將通知有關(guān)的視圖。
  • 視圖view是它在屏幕上的表示,描繪的是model的當(dāng)前狀態(tài)。當(dāng)模型的數(shù)據(jù)發(fā)生變化,視圖相應(yīng)地得到刷新自己的機會。
  • 控制器controller定義用戶界面對用戶輸入的響應(yīng)方式,起到不同層面間的組織作用,用于控制應(yīng)用程序的流程,它處理用戶的行為和數(shù)據(jù)model上的改變。 

經(jīng)典MVC模式

實線:方法調(diào)用 虛線:事件通知

其中涉及兩種設(shè)計模式:

  • view和model之間的觀察者模式,view觀察model,事先在此model上注冊,以便view可以了解在數(shù)據(jù)model上發(fā)生的改變。
  • view和controller之間的策略模式

一個策略是一個表述算法的對象,MVC允許在不改變視圖外觀的情況下改變視圖對用戶輸入的響應(yīng)方式。例如,你可能希望改變視圖對鍵盤的響應(yīng)方式,或希望使用彈出菜單而不是原來的命令鍵方式。MVC將響應(yīng)機制封裝在controller對象中。存在著一個controller的類層次結(jié)構(gòu),使得可以方便地對原有的controller做適當(dāng)改變而創(chuàng)建新的controller。

view使用controller子類的實例來實現(xiàn)一個特定的響應(yīng)策略。要實現(xiàn)不同的響應(yīng)的策略只要用不同種類的controller實例替換即可。甚至可以在運行時刻通過改變view的controller來改變用戶輸入的響應(yīng)方式。例如,一個view可以被禁止接受任何輸入,只需給他一個忽略輸入事件的controller。

好吧,如果被上述言論繞昏了,請繼續(xù)研讀《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》。

MVC for JAVASCRIPT

我們回顧了經(jīng)典的MVC,接下來講到的MVC主要是在Javascript上的實現(xiàn)。

javascript MVC模式

源圖

如圖所示,view承接了部分controller的功能,負責(zé)處理用戶輸入,但是不必了解下一步做什么。它依賴于一個controller為她做決定或處理用戶事件。事實上,前端的view已經(jīng)具備了獨立處理用戶事件的能力,如果每個事件都要流經(jīng)controller,勢必增加復(fù)雜性。同時,view也可以委托controller處理model的更改。model數(shù)據(jù)變化后通知view進行更新,顯示給用戶。這個過程是一個圓,一個循環(huán)的過程。

這種從經(jīng)典MVC到Javascript MVC的1對1轉(zhuǎn)化,導(dǎo)致控制器的角色有點尷尬。MVC這樣的結(jié)構(gòu)的正確性在于,任何界面都需要面對一個用戶,而controller “是用戶和系統(tǒng)之間的鏈接”。在經(jīng)典MVC中,controller要做的事情多數(shù)是派發(fā)用戶輸入給不同的view,并且在必要的時候從view中獲取用戶輸入來更改model,而Web以及絕大多數(shù)現(xiàn)在的UI系統(tǒng)中,controller的職責(zé)已經(jīng)被系統(tǒng)實現(xiàn)了。由于某種原因,控制器和視圖的分界線越來越模糊,也有認為,view啟動了action理論上應(yīng)該把view歸屬于controller。比如在Backbone中,Backbone.View和Backbone.Router一起承擔(dān)了controller的責(zé)任。這就為MVC中controller的衍變埋下了伏筆。

MVP

MVP(model-view-Presenter)是經(jīng)典MVC設(shè)計模式的一種衍生模式,是在1990年代Taligent公司創(chuàng)造的,一個用于C++ CommonPoint的模型。背景上不再考證,直接上圖看一下與MVC的不同。

MVP模式

經(jīng)典MVC中,一對controller-view捆綁起來表示一個ui組件,controller直接接受用戶輸入,并將輸入轉(zhuǎn)為相應(yīng)命令來調(diào)用model的接口,對model的狀態(tài)進行修改,***通過觀察者模式對view進行重新渲染。

進化為MVP的切入點是修改controller-view的捆綁關(guān)系,為了解決controller-view的捆綁關(guān)系,將進行改造,使view不僅擁有UI組件的結(jié)構(gòu),還擁有處理用戶事件的能力,這樣就能將controller獨立出來。為了對用戶事件進行統(tǒng)一管理,view只負責(zé)將用戶產(chǎn)生的事件傳遞給controller,由controller來統(tǒng)一處理,這樣的好處是多個view可共用同一個controller。此時的controller也由組件級別上升到了應(yīng)用級別,然而更新view的方式仍然與經(jīng)典MVC一樣:通過Presenter更新model,通過觀察者模式更新view。

另一個顯而易見的不同在于,MVC是一個圓,一個循環(huán)的過程,但MVP不是,依賴Presenter作為核心,負責(zé)從model中拿數(shù)據(jù),填充到view中。常見的MVP的實現(xiàn)是被動視圖(passive view),Presenter觀察model,不再是view觀察model,一旦model發(fā)生變化,就會更新view。Presenter有效地綁定了model到view。view暴露了setters接口以便Presenter可以設(shè)置數(shù)據(jù)。對于這種被動視圖的結(jié)構(gòu),沒有直接數(shù)據(jù)綁定的概念。但是他的好處是在view和model直接提供更清晰的分離。但是由于缺乏數(shù)據(jù)綁定支持,意味著不得不單獨關(guān)注某個任務(wù)。在MVP里,應(yīng)用程序的邏輯主要在Presenter來實現(xiàn),其中的view是很薄的一層。

MVVM

MVVM,Model-View-ViewModel,最初是由微軟在使用Windows Presentation Foundation和SilverLight時定義的,2005年John Grossman在一篇關(guān)于Avalon(WPF 的代號)的博客文章中正式宣布了它的存在。如果你用過Visual Studio, 新建一個WPF Application,然后在“設(shè)計”中拖進去一個控件、雙擊后在“代碼”中寫事件處理函數(shù)、或者綁定數(shù)據(jù)源。就對這個MVVM有點感覺了。比如VS自動生成的如下代碼:

 
 
 
 
  1.  
  2.      
  3.          
  4.          
  5.          
  6.          
  7.          
  8.          
  9.          
  10.          
  11.      
  12.   
 
 
 
 
  1. stackPanel1.DataContext = new Student() { 
  2.     StudentID=20130501, 
  3.     Name="張三", 
  4.     EntryDate=DateTime.Parse("2013-09-01"), 
  5.     Credit=0.0 
  6. }; 

其中最重要的特性之一就是數(shù)據(jù)綁定,Data-binding。沒有前后端分離,一個開發(fā)人員全搞定,一只手抓業(yè)務(wù)邏輯、一只手抓數(shù)據(jù)訪問,順帶手拖放幾個UI控件,綁定數(shù)據(jù)源到某個對象或某張表,一步到位。

背景介紹完畢,再來看一下理論圖

MVVM模式

首先,view和model是不知道彼此存在的,同MVP一樣,將view和model清晰地分離開來。 其次,view是對viewmodel的外在顯示,與viewmodel保持同步,viewmodel對象可以看作是view的上下文。view綁定到viewmodel的屬性上,如果viewmodel中的屬性值變化了,這些新值通過數(shù)據(jù)綁定會自動傳遞給view。反過來viewmodel會暴露model中的數(shù)據(jù)和特定狀態(tài)給view。 所以,view不知道m(xù)odel的存在,viewmodel和model也覺察不到view。事實上,model也完全忽略viewmodel和view的存在。這是一個非常松散耦合的設(shè)計。

流行的MV*框架:

每個框架都有自己的特性,這里主要討論MVC三個角色的責(zé)任。粗淺地過一遍每個框架的代碼結(jié)構(gòu)和風(fēng)格。

BackboneJS

Backbone通過提供模型Model、集合Collection、視圖View賦予了Web應(yīng)用程序分層結(jié)構(gòu),其中模型包含領(lǐng)域數(shù)據(jù)和自定義事件;集合Colection是模型的有序或無序集合,帶有豐富的可枚舉API; 視圖可以聲明事件處理函數(shù)。最終將模型、集合、視圖與服務(wù)端的RESTful JSON接口連接。

Backbone在升級的過程中,去掉了controller,由view和router代替controller,view集中處理了用戶事件(如click,keypress等)、渲染HTML模板、與模型數(shù)據(jù)的交互。Backbone的model沒有與UI視圖數(shù)據(jù)綁定,而是需要在view中自行操作DOM來更新或讀取UI數(shù)據(jù)。Router為客戶端路由提供了許多方法,并能連接到指定的動作(actions)和事件(events)。

Backbone是一個小巧靈活的庫,只是幫你實現(xiàn)一個MVC模式的框架,更多的還需要自己去實現(xiàn)。適合有一定Web基礎(chǔ),喜歡原生JS去操作DOM(因為沒有數(shù)據(jù)綁定)的開發(fā)人員。為什么稱它為庫,而不是框架,不僅僅是由于僅4KB的代碼,更重要的是 使用一個庫,你有控制權(quán)。如果用一個框架,控制權(quán)就反轉(zhuǎn)了,變成框架在控制你。庫能夠給予靈活和自由,但是框架強制使用某種方式,減少重復(fù)代碼。這便是Backbone與Angular的區(qū)別之一了。

至于Backbone屬于MV*中的哪種模式,有人認為不是MVC,有人覺得更接近于MVP,事實上,它借用多個架構(gòu)模式中一些很好的概念,創(chuàng)建一個運行良好的靈活框架。不必拘泥于某種模式。

 
 
 
 
  1. // view: 
  2. var Appview = Backbone.View.extend({ 
  3.     // 每個view都需要一個指向DOM元素的引用,就像ER中的main屬性。 
  4.     el: '#container', 
  5.  
  6.     // view中不包含html標(biāo)記,有一個鏈接到模板的引用。 
  7.     template: _.template("

    Hello <%= who %>

    "), 
  8.  
  9.     // 初始化方法 
  10.     initialize: function(){ 
  11.       this.render(); 
  12.     }, 
  13.  
  14.     // $el是一個已經(jīng)緩存的jQuery對象 
  15.     render: function(){ 
  16.       this.$el.html("Hello World"); 
  17.     }, 
  18.  
  19.     // 事件綁定 
  20.     events: {'keypress #new-todo': 'createTodoOnEnter'} 
  21. }); 
  22. var appview = new Appview(); 
  23.  
  24. // model: 
  25. // 每個應(yīng)用程序的核心、包含了交互數(shù)據(jù)和邏輯 
  26. // 如數(shù)據(jù)驗證、getter、setter、默認值、數(shù)據(jù)初始化、數(shù)據(jù)轉(zhuǎn)換 
  27. var app = {}; 
  28.  
  29. app.Todo = Backbone.model.extend({ 
  30.   defaults: { 
  31.     title: '', 
  32.     completed: false 
  33.   } 
  34. }); 
  35.  
  36. // 創(chuàng)建一個model實例 
  37. var todo = new app.Todo({title: 'Learn Backbone.js', completed: false}); 
  38. todo.get('title'); // "Learn Backbone.js" 
  39. todo.get('completed'); // false 
  40. todo.get('created_at'); // undefined 
  41. todo.set('created_at', Date()); 
  42. todo.get('created_at'); // "Wed Sep 12 2012 12:51:17 GMT-0400 (EDT)" 
  43.  
  44. // collection: 
  45. // model的有序集合,可以設(shè)置或獲取model 
  46. // 監(jiān)聽集合中的數(shù)據(jù)變化,從后端獲取模型數(shù)據(jù)、持久化。 
  47. app.TodoList = Backbone.Collection.extend({ 
  48.   model: app.Todo, 
  49.   localStorage: new Store("backbone-todo") 
  50. }); 
  51.  
  52. // collection實例 
  53. var todoList = new app.TodoList() 
  54. todoList.create({title: 'Learn Backbone\'s Collection'}); 
  55.  
  56. // model實例 
  57. var model = new app.Todo({title: 'Learn models', completed: true}); 
  58. todoList.add(model); 
  59. todoList.pluck('title'); 
  60. todoList.pluck('completed'); 

KnockoutJS

KnockoutJS是一個名正言順的MVVM框架,通過簡潔易讀的data-bind語法,將DOM元素與viewmodel關(guān)聯(lián)起來。當(dāng)模型(viewmodel)狀態(tài)更新時,自動更新UI界面。 viewmodel是model和view上的操作的一個連接,是一個純粹的Javascript對象。它不是UI,沒有控件和樣式的概念,它也不是持久化的模型數(shù)據(jù),它只是hold住一些用戶正在編輯的數(shù)據(jù),然后暴露出操作這些數(shù)據(jù)(增加或刪除)的方法。

view是對viewmodel中數(shù)據(jù)的一個可視化的顯示,view觀察viewmodel,操作view時會發(fā)送命令到viewmodel,并且當(dāng)viewmodel變化時更新。view和model是不了解彼此的存在的。

 
 
 
 
  1.  
  2.     New item: 
  3.      
  4.      0">Add 
  5.     

    Your items:

     
  6.       
  7.  
 
 
 
 
  1. // viewmodel 
  2. var SimpleListmodel = function(items) { 
  3.     this.items = ko.observableArray(items); 
  4.     this.itemToAdd = ko.observable(""); 
  5.     this.addItem = function() { 
  6.         if (this.itemToAdd() != "") { 
  7.             // 把input中的值加入到items,會自動更新select控件 
  8.             this.items.push(this.itemToAdd()); 
  9.             // 清空input中的值 
  10.             this.itemToAdd(""); 
  11.         } 
  12.     // 確保這里的this一直是viewmodel 
  13.     }.bind(this); 
  14. }; 
  15.  
  16. ko.applyBindings(new SimpleListmodel(["Alpha", "Beta", "Gamma"])); 

AngularJS

AngularJS試圖成為Web應(yīng)用中的一種端對端的解決方案。這意味著它不只是你的Web應(yīng)用中的一個小部分,而是一個完整的端對端的解決方案。這會讓AngularJS在構(gòu)建一個CRUD的應(yīng)用時看起來很呆板,缺乏靈活性。AngularJS是為了克服HTML在構(gòu)建應(yīng)用上的不足而設(shè)計的。使用了不同的方法,它嘗試去補足HTML本身在構(gòu)建應(yīng)用方面的缺陷。通過使用標(biāo)識符(directives)的結(jié)構(gòu),讓瀏覽器能夠識別新的語法。例如使用雙大括號語法進行數(shù)據(jù)綁定;使用ng-controller指定每個控制器負責(zé)監(jiān)視視圖中的哪一部分;使用ng-model,把輸入數(shù)據(jù)綁定到模型中的一部分屬性上。

雙向數(shù)據(jù)綁定是AngularJS的另一個特性。UI控件的任何更改會立即反映到模型變量(一個方向),模型變量的任何更改都會立即反映到問候語文本中(另一方向)。AngularJS通過作用域來保持數(shù)據(jù)模型與視圖界面UI的雙向同步。一旦模型狀態(tài)發(fā)生改變,AngularJS會立即刷新反映在視圖界面中,反之亦然。

AngularJS原本是傾向于MVC,但是隨著項目重構(gòu)和版本升級,現(xiàn)在更接近MVVM。和Knockout view中的風(fēng)格類似,都像從WPF衍變過來的,只是Knockout使用了自定義屬性data-bind作為綁定入口,而AngularJS對于HTML的變革更徹底,擴展HTML的語法,引入一系列的指令。

在AngularJS中,一個視圖是模型通過HTML模板渲染之后的映射。這意味著,不論模型什么時候發(fā)生變化,AngularJS會實時更新結(jié)合點,隨之更新視圖。比如,視圖組件被AngularJS用下面這個模板構(gòu)建出來:

 
 
 
 
  1.  
  2.     
       
    •          
    •             {{phone.name}} 
    •             

      {{phone.snippet}}

       
    •         
    •  
    •     
     
  3.  

在li標(biāo)簽里面的ng-repeat語句是一個AngularJS迭代器。包裹在phone.name和phone.snippet周圍的花括號標(biāo)識著數(shù)據(jù)綁定,是對應(yīng)用一個數(shù)據(jù)模型的引用。當(dāng)頁面加載的時候,AngularJS會根據(jù)模版中的屬性值,將其與數(shù)據(jù)模型中相同名字的變量綁定在一起,以確保兩者的同步性。

在PhoneListCtrl控制器里面初始化了數(shù)據(jù)模型:

 
 
 
 
  1. // controller: 
  2. function PhoneListCtrl($scope) { 
  3.   // 數(shù)組中存儲的對象是手機數(shù)據(jù)列表 
  4.   $scope.phones = [ 
  5.     {"name": "Nexus S", 
  6.      "snippet": "Fast just got faster with Nexus S."}, 
  7.     {"name": "Motorola XOOM? with Wi-Fi", 
  8.      "snippet": "The Next, Next Generation tablet."}, 
  9.     {"name": "MOTOROLA XOOM?", 
  10.      "snippet": "The Next, Next Generation tablet."} 
  11.   ]; 

盡管控制器看起來并沒有什么控制的作用,但是它在這里的重要性在于,通過給定數(shù)據(jù)模型的作用域$scope,允許建立模型和視圖之間的數(shù)據(jù)綁定。方法名PhoneListCtrl和body標(biāo)簽里面的ngcontroller指令的值相匹配。當(dāng)應(yīng)用啟動之后,會有一個根作用域被創(chuàng)建出來,而控制器的作用域是根作用域的一個典型后繼。這個控制器的作用域?qū)λ?/p>

標(biāo)記內(nèi)部的數(shù)據(jù)綁定有效。

AngularJS的作用域理論非常重要:一個作用域可以視作模板、模型和控制器協(xié)同工作的粘接器。AngularJS使用作用域,同時還有模板中的信息,數(shù)據(jù)模型和控制器。這些可以幫助模型和視圖分離,但是他們兩者確實是同步的!任何對于模型的更改都會即時反映在視圖上;任何在視圖上的更改都會被立刻體現(xiàn)在模型中。

實踐中的思考

我們使用的MVC框架是ER,適用于并能很方便地構(gòu)建一個整站式的AJAX Web應(yīng)用。提供精簡、核心的action、model和view的抽象,使得構(gòu)建RIA應(yīng)用變得簡單可行。在使用的過程中近距離地體會到非常多方面的優(yōu)秀的設(shè)計理念。也讓我開始思考各個角色的轉(zhuǎn)型。

讓view上前線

我開始思考action(controller)這個角色。我覺得從純粹地解耦角度來說,view和model應(yīng)該是互相不知道彼此存在的,所有的事件流和對數(shù)據(jù)、UI的處理應(yīng)該都流經(jīng)action。但是這一點又極不現(xiàn)實。用戶操作了一個UI,需要更新model的一個數(shù)據(jù),就要fire到action,通過action來調(diào)用model的set方法。這樣又有點麻煩,因為view中有對model的應(yīng)用,可以一句代碼搞定這一個數(shù)據(jù)的設(shè)置。所以,我自己設(shè)置了一個規(guī)則:如果是簡單的模型數(shù)據(jù)讀寫可以直接在view中操作;如果要經(jīng)過復(fù)雜的數(shù)據(jù)處理,必須流經(jīng)action。于是,我遇到了一種怎么都偷不了懶(必須經(jīng)過action)的情況: 比如有個主action main,兩個子action list、select,用戶在list中的view選擇一條數(shù)據(jù)添加到右側(cè)select中。那走過的流程是這樣的:

實踐中的思考

  1. 子Action中的listView接受UI事件,fire到listAction中
  2. listAction繼續(xù)將事件fire到mainView中,由主action來處理另外子Action的事情。
  3. mainView接收到事件、調(diào)用子Action selectAction的方法
  4. selectAction繼續(xù)調(diào)用selectView的方法來完成UI的更新。

其中涉及的model的變化暫時不考慮。我在想,view既然把經(jīng)典MVC中的controller接受用戶事件的角色承接過來的,那如果借鑒Backbone的思想,把view作為controller的一個實現(xiàn),推到戰(zhàn)場的最前線。省掉兩次action的中轉(zhuǎn)傳遞,是不是更簡單。

model驅(qū)動開發(fā)

實際開發(fā)中,常常會以view為核心,頁面上需要展示什么數(shù)據(jù),就去model中設(shè)置數(shù)據(jù)源。發(fā)生了用戶事件,我會在action中更新model,然后刷新view。有時候會遺漏更新model,直到需要數(shù)據(jù)時才發(fā)現(xiàn)沒有保存到model中。

model本身是獨立的,自控制的,不依賴于view,能夠同步支持多view的顯示。就像linux上的應(yīng)用程序通常會提供圖形界面和命令行兩種操作方式一樣。那如果以model為核心,model驅(qū)動開發(fā),數(shù)據(jù)在手、天下我有,以模型驗證保證數(shù)據(jù)的完整性和正確性。實現(xiàn)數(shù)據(jù)綁定,任何對模型的更改都會在界面上反映出來。那我們只要預(yù)先寫好view和model的關(guān)系映射(類似viewmodel),然后只關(guān)注模型數(shù)據(jù),就OK了。


分享題目:前端MVC變形記
分享路徑:http://www.5511xx.com/article/dhdhocp.html