前端MVVM模式及其在Vue和React中的體現

MVVM相關概念


1) MVVM典型特色是有四個概念:Model、View、ViewModel、綁定器。MVVM能夠是單向綁定也能夠是雙向綁定甚至是不綁定
2) 綁定器:聲明性的數據和命令,存在於ViewModel之中,讓ViewModel和Model兩者進行自動或手動通訊,接下來的「MVVM在React中對應關係」小節有舉例說明。
3) MVVM本質上是M- V-C-VM,它是在MVC的基礎上增長了一層VM,只不過C變弱了,被併入到M概念中,VM用於分離V和M,而且讓用戶避免因爲直接操做V層的DOM而帶來的繁瑣和效率低下,MVVM使開發更高效,結構更清晰,增長代碼的複用性。
4) 在不一樣的GUI(圖形用戶界面)上進行展現時,Model、Controller、View-Model可以複用,只需把View層進行替換。
5) 在不一樣類型的UI(用戶界面)上進行展現時,Model、Controller可以複用,只需把View-Model、View層進行替換。好比:假設咱們開發的是一款針對盲人的應用,那麼輸出設備或許咱們須要考慮使用揚聲器來代替顯示器,輸入設備使用麥克風,這時咱們只需將上述的View-Model替換爲Audio-Model做爲語音模型,將 V(iew)層替換爲Audio層用於播放語音和接收語音輸入。
6) 我的認爲:在基於MVVM框架的項目中,不論是雙向數據綁定仍是單向數據綁定,你在開發中實際要面對的都是ViewModel和M(odel)層以前的通訊,由於V(iew) 和ViewModel層之間的映射和通訊都是由框架自動完成的,vue

MVVM四層結構


1) M(odel)層:模型,定義數據結構。
2) C(ontroller)層:實現業務邏輯,數據的增刪改查。在MVVM模式中通常把C層算在M層中,(只有在理想的雙向綁定模式下,Controller 纔會徹底的消失。這種理想狀態通常不存在)
3) ViewModel層:顧名思義是視圖View的模型、映射和顯示邏輯(如if for等,非業務邏輯),另外綁定器也在此層。ViewModel是基於視圖開發的一套模型,若是你的應用是給盲人用的,那麼也能夠開發一套基於Audio的模型AudioModel。
4) V(iew)層:將ViewModel經過特定的GUI展現出來,並在GUI控件上綁定視圖交互事件,V(iew)通常由MVVM框架自動生成在瀏覽器中。react

MVVM在React中對應關係


1) M(odel):對應組件的方法或生命週期函數中實現的業務邏輯和this.state中保存的本地數據,若是React集成了redux +react-redux,那麼組件中的業務邏輯和本地數據能夠徹底被解耦出來單獨存放當作M層,如業務邏輯放在Reducer和Action中。
2) V(iew)-M(odel):對應組件中的JSX,它實質上是Virtual DOM的語法糖。React負責維護 Virtual DOM以及對其進行diff運算,而React-dom 會把Virtual DOM渲染成瀏覽器中的真實DOM
3) View:對應框架在瀏覽器中基於虛擬DOM生成的真實DOM(並不須要咱們本身書寫)以及咱們書寫的CSS
4)綁定器:對應JSX中的命令以及綁定的數據,如className={ this.props.xxx }、{this.props.xxx}等等redux

MVVM的雙綁和單綁區別


1) 通常,只有UI表單控件才存在雙向數據綁定,非UI表單控件只有單向數據綁定。
2) 單向數據綁定是指:M的變化能夠自動更新到ViewModel,但ViewModel的變化須要手動更新到M(經過給表單控件設置事件監聽)
3) 雙向數據綁定是指念:M的變化能夠自動更新到ViewModel,ViewModel的變化也能夠自動更新到M
4) 雙向綁定 = 單向綁定 + UI事件監聽。雙向和單向只不過是框架封裝程度上的差別,本質上二者是能夠相互轉換的。
5) 優缺點:在表單交互較多的狀況下,單向數據綁定的優勢是數據更易於跟蹤管理和維護,缺點是代碼量較多比較囉嗦,雙向數據綁定的優缺點和單向綁定正好相反。segmentfault

三大框架的異同


1) 三大框架都是數據驅動型的框架
2) vue及angular是雙向數據綁定;react是單向數據綁定。React貌似使用的也是Object.defineProperty監控數據,只是沒有進一步把表單控件的事件封裝進v-model
3) Vuex、Redux都是單項數據綁定的,即M的變化能夠自動更新到V,但V的變化必須手動觸發事件更新到M,這種單項數據綁定使數據更易於跟蹤管理和維護。
4) 未完待續……瀏覽器

Vue雙向綁定原理


1) Vue的雙向數據綁定是經過Object.defineProperty的get/set對M層數據進行監控,當數據發生變化時,自動更新VM層綁定的數據,而當用戶更改了VM層表單控件的數據時,經過v-model自動更新到M層(v-model是對錶單控件的事件的封裝)
精簡示例:數據結構

<div id="demo"></div>
<input type="text" id="inp">
<script>
  var obj = {}
  var demo = document.querySelector('#demo')
  var inp = document.querySelector('#inp')
  Object.defineProperty(obj, 'name', { // 看起來數據name只是做爲數據中轉的做用,真正要更新到view層的數據操做在set方法裏。
    get: function() {
      return 0
    },
    set: function (newVal) {
      inp.value = newVal
      demo.innerHTML = newVal
    }
  })
  inp.addEventListener('input', function(e) {
    obj.name = e.target.value  // 給obj的name屬性賦值,進而觸發該屬性的set方法,
  })
  obj.name = 'fei'// 在給obj設置name屬性的時候,觸發了set這個方法
</script>

2)咱們已經知道Vue是雙向數據綁定(經過v-model),Vuex是單向數據綁定,那麼問題來了,在基於Vue+ Vuex的項目中,Vuex中的數據是不容許Vue的v-model對其進行更改的,會報錯,有以下三種解決方案:框架

  • 依然使用v-model,數據不放進Vuex中,而是放在組件自身的data屬性中
  • 依然使用v-model,不過取值再也不是Vuex中的數據,而是組件自身的一個computed(getter/setter)或watch,經過computed或watch裏的回調來把數據變化提交(commit)到Vuex
    組件模板:dom

    <template>
      <div>
         <input  type="text" v-model="newName"/>
         <p>{{newName}}</p>
      </div>
    </template>

    組件VUE實例:函數

    computed: {
        newName: {
          get () {
            return this.$store.state.name
          },
          set (val) {
            this.$store.commit('changeName', val) //當newName 值發生改變時,提交一個mutation:changeName,用於改變store中的name/
          }
        }
      }

    mutation:this

    changeName (state, val) {
       state.name = val
     }
  • 不使用v-model,經過UI事件監聽觸發一個回調,而後手動把數據變化提交(commit)到Vuex

3)Vue的雙向數據綁定和Vue的prop的單項數據流是兩個不一樣的概念,數據綁定的前提是有數據流,但有數據流不必定有數據綁定。prop的單項數據流是指:prop能夠把父組件的數據傳遞給子組件而且子組件不能對該數據進行直接修改更不能迴流到父組件(固然,得益於Vue對全部數據使用了Object.defineProperty,因此prop傳遞的數據是綁定的,即父組件中該數據一旦發生變化,子組件中的也跟着變化)

來源:http://www.javashuo.com/article/p-ninzmzcl-hz.html

相關文章
相關標籤/搜索