欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

老生常談js中的MVC

 更新時間:2017年07月25日 08:14:08   投稿:jingxian  
下面小編就為大家?guī)硪黄仙U刯s中的MVC。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

MVC是什么?

MVC是一種架構模式,它將應用抽象為3個部分:模型(數據)、視圖、控制器(分發(fā)器)。

本文將用一個經典的例子todoList來展開(代碼在最后)。

一個事件發(fā)生的過程(通信單向流動):

1、用戶在視圖 V 上與應用程序交互

2、控制器 C 觸發(fā)相應的事件,要求模型 M 改變狀態(tài)(讀寫數據)

3、模型 M 將數據發(fā)送到視圖 V ,更新數據,展現給用戶

js傳統(tǒng)開發(fā)模式,大多基于事件驅動的

1、hash驅動

2、DOM事件,用來驅動視圖

3、模型事件(業(yè)務模型事件和數據模型事件),用來驅動模型和模型結合

所以js中的mvc的特點是:單向流動、事件驅動

一)模型

模型存放應用的所有數據對象業(yè)務數據、數據校驗、增刪改查),比如,例子todoList中的store模型,存放每一條記錄與之有關的邏輯。

數據是面向對象的,當控制器請求模型讀寫數據時,模型就將數據包裝成模型實例。任何定義在這個數據模型上的函數或邏輯都可以直接被調用。在本文的例子中采用localSrorage也是類似道理的。存儲的Todos可以隨時被調用

模型不關心,不包含視圖和控制器的邏輯。它們應該是互相解耦的。這里提一點,模型視圖的耦合,顯然是違反MVC架構原則,但往往我們有時候卻因為業(yè)務關系而無法完全解耦

模型表現了領域特定的數據,當一個模型有所改變的時候,它會通知它的觀察者(視圖)。

二)視圖

視圖是呈現給用戶的,是用戶交互的第一入口。它定義配置、管理著每個頁面相應的模板與組件,它表現一個模型的當前狀態(tài),視圖通過觀察者模式監(jiān)視模型,以獲得最新的數據,來呈現最新的頁面。所以,頁面首次加載時,往往是從接收模型的數據開始。

三)控制器

控制器分發(fā)器),是模型和視圖之間的橋梁,集中式配置和管理事件分發(fā)、模型分發(fā)、視圖分發(fā),還用來權限控制、異常處理等。我們的應用中往往是有多個控制器的

頁面加載完成后,控制器監(jiān)聽視圖的用戶交互按鈕點擊或表單提交,一旦用戶發(fā)生交互時,控制器做出對視圖的選擇,觸發(fā)控制器的事件處理機制去派發(fā)新的事件,通知模型更新數據(這樣就回到了第一步了)

Demo-todoList

最后這里是一個用原生js寫的todoLIst,這個demo做的很簡陋,點擊輸入文字點擊確定就添加,刪除是直接點擊該行信息。

單獨分離開來舉例子不好講,所以在代碼中進行注釋。首先簡單理下下邊代碼的思路:

1、V層定義配置了一個顯示數據的字符串模板,同時定義一個訂閱者的回調函數render() 用于頁面更新數據。

2、C層監(jiān)聽用戶的添加與刪除操作,添加是add() 函數 它執(zhí)行了回調函數render,同時向M層寫入數據,通知M層改變。刪除操作同理。

3、M層是本地存儲localStorage,模擬一個存儲數據對象的后臺模型。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>todo</title>
</head>
<body>
<header>
 <h3>待定事項</h3>
</header>
<main>
 <ul id="todoList"></ul>
 <input type="text" id="content">
 <button id="confirm">確認</button>
</main>

<script>
 (function () {
 const ADD_KEY = '__todoList__'

 const Utils = {
  // 模擬 Modal(實體模型)
  store(key, data) {
  if (arguments.length > 1) {
   return localStorage.setItem(key, JSON.stringify(data));
  } else {
   let storeData = localStorage.getItem(key);
   return (storeData && JSON.parse(storeData)) || []; // 這里一定要設置初始值為 []
  }
  }
 }

 class Todo {
  constructor(id, text = "") {
  this.id = id
  this.text = text
  }
 }

 let App = {
  init() {
  // this.todos 為一個存儲json對象的數組, 是一個實例化的數據對象,可任意調用
  this.todos = Utils.store(ADD_KEY)
  this.findDom()
  this.bindEvent()
  this.render() // 初始化渲染
  },


  findDom() {
  this.contentBox = document.querySelector("#content")
  this.confirm = document.querySelector("#confirm")
  this.todoList = document.querySelector("#todoList")
  this.todoListItem = document.getElementsByTagName("li")
  },

  // 模擬 Controller (業(yè)務邏輯層)
  bindEvent() {
  this.confirm.addEventListener('click', () => {
   // 要求模型 M 改變狀態(tài),add()函數是寫入數據操作
   this.add()
  }, false)

  this.todoList.addEventListener('click', (item) => { // 事件委托,優(yōu)化性能
   this.remove(item)
  }, false)
  },

  // 這里勉強抽象成一個視圖吧!!!
  view() {
  let fragment = document.createDocumentFragment() // 減少回流次數
  fragment = ''

  for (let i = 0; i < this.todos.length; i++) { // 一次性DOM節(jié)點生成
   // 這里使用拼接字符串代替視圖的模板,
   // *******注意模板并不是一個視圖,模板是由視圖定義配置出來的,并被其管理著*******
   // 模板是用一種聲明的方式指定部分甚至所有的視圖對象
   fragment += `<li>${this.todos[i].text}</li>`
  }
  this.todoList.innerHTML = fragment
  },

  // render()函數作為一個訂閱者的回調函數,數據的變化會反饋到模型 store
  // 換句話說:視圖通過觀察者模式,觀察模型 store,當模型發(fā)生改變,觸發(fā)視圖更新
  render() {
  this.view()

  /**
   * 這里需要特別提一下,按照 MVC 原則這里本不應該出現下面的代碼的
   * 因為業(yè)務邏輯關系(我本地存儲使用的是同一個key值,再次寫入數據會覆蓋原來的數據,),
   * 所以必須通知模型 M 保存數據, V 層處理了不該它處理的邏輯,導致 M 與 V 耦合
   *
   * 解決辦法是:將其抽象出來編寫一個 視圖助手 helper
   */
  Utils.store(ADD_KEY, this.todos)
  },

  getItemIndex(item) {
  let itemIndex
  if (item.target.tagName.toLowerCase() === 'li') {
   let arr = Array.prototype.slice.call(this.todoListItem)
   let index = arr.indexOf(item.target)
   return itemIndex = index
  }
  },

  add(e) {
  let id = Number(new Date())
  let text = this.contentBox.value
  let addTodo = new Todo(id, text)
  this.todos.unshift(addTodo) // 模型發(fā)生改變
  this.render() // 當模型發(fā)生改變,觸發(fā)視圖更新
  },

  remove(item) {
  let index = this.getItemIndex(item)
  this.todos.splice(index, 1)
  this.render()
  }
 }

 App.init()
 })()
</script>
</body>
</html>

隨著界面和邏輯的復雜,用js或者jq去控制DOM不現實的。上邊例子只是用原生js模擬mvc的思想實現過程。真正地項目往往會依賴一些封裝好的優(yōu)秀庫進行高效開發(fā)。

mvc模式的優(yōu)點

mvc編程把所有精力放在數據處理,盡可能減少對網頁元素的處理。對于一定數量功能的網頁,Mvc模式下強制規(guī)范代碼,簡化減少重復代碼,使代碼易于擴充。

mvc模式的弊端

1、清晰的構架以代碼的復雜性為代價, 對小項目反而降低開發(fā)效率。 (如果本文的例子todoList用面條式代碼編寫,那得多簡單啊?。。。?br /> 2、控制層和視圖層耦合,導致沒有真正分離和重用

3、在同一業(yè)務邏輯下,如果存在多種視圖呈現,需要視圖定義配置多個模板引擎、數據解析,多次處理數據與頁面更新。代碼就充滿了各種選擇器與事件回調,隨著業(yè)務的膨脹,變得難以維護。

總結:其實,現在MVC在前端用得比較少了,因為它的局限性,催生了MVVM模式的流行與廣泛使用,在下篇文章我會談談我對MVVM的理解,以及為何我使用基于MVVM模式的vue框架來高效開發(fā)。

以上這篇老生常談js中的MVC就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • JavaScript設計模式經典之命令模式

    JavaScript設計模式經典之命令模式

    命令模式(Command)的定義是:用來對方法調用進行參數化處理和傳送,經過這樣處理過的方法調用可以在任何需要的時候執(zhí)行。接下來通過本文給大家介紹JavaScript設計模式經典之命令模式,需要的朋友參考下
    2016-02-02
  • JS模擬實現方法重載示例

    JS模擬實現方法重載示例

    這篇文章主要介紹了JS模擬實現方法重載,涉及js基于arguments實現重載的相關技巧,需要的朋友可以參考下
    2016-08-08
  • 點擊A元素觸發(fā)B元素的事件在IE8下會識別成A元素

    點擊A元素觸發(fā)B元素的事件在IE8下會識別成A元素

    IE8自動觸發(fā)的事件源會識別成手動點擊的元素就是點擊A元素觸發(fā)B元素的事件在IE8下會識別成A元素,需要的朋友可以參考下
    2014-09-09
  • js上傳圖片及預覽功能實例分析

    js上傳圖片及預覽功能實例分析

    這篇文章主要介紹了js上傳圖片及預覽功能,實例分析了javascript操作圖片上傳預覽功能的實現方法,需要的朋友可以參考下
    2015-04-04
  • JavaScript 反科里化 this [譯]

    JavaScript 反科里化 this [譯]

    本文主要講了JavaScript中科里化和反科里化this的方法.話題來自于Brendan Eich(JavaScript之父)的一個tweet
    2012-09-09
  • 純javascript響應式樹形菜單效果

    純javascript響應式樹形菜單效果

    這篇文章主要為大家分享了純javascript響應式樹形菜單效果的簡單教程,對多級目錄樹形菜單感興趣的小伙伴們可以參考一下
    2015-11-11
  • ES6入門教程之let、const的使用方法

    ES6入門教程之let、const的使用方法

    這篇文章主要給大家介紹了關于ES6入門教程之let、const使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用ES6具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • 基于javascript實現日歷功能原理及代碼實例

    基于javascript實現日歷功能原理及代碼實例

    這篇文章主要介紹了基于javascript實現日歷效果原理及代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • JS圖片延遲加載插件LazyImgv1.0用法分析【附demo源碼下載】

    JS圖片延遲加載插件LazyImgv1.0用法分析【附demo源碼下載】

    這篇文章主要介紹了JS圖片延遲加載插件LazyImgv1.0用法,結合實例形式分析了使用圖片延遲加載插件LazyImgv1.0的注意事項與核心操作技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下
    2017-09-09
  • JavaScript中Iterator迭代器接口和循環(huán)

    JavaScript中Iterator迭代器接口和循環(huán)

    這篇文章主要介紹了JavaScript中Iterator迭代器接口和循環(huán),迭代器是數據結構遍歷的一種機制迭代器主要是提供for...of使用,更多相關內推需要的小伙伴可以參考下面文章內容
    2022-06-06

最新評論