溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

js中的MVC是什么

發(fā)布時(shí)間:2021-08-18 20:59:49 來(lái)源:億速云 閱讀:146 作者:chen 欄目:web開(kāi)發(fā)

本篇內(nèi)容主要講解“js中的MVC是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“js中的MVC是什么”吧!

MVC是什么?

MVC是一種架構(gòu)模式,它將應(yīng)用抽象為3個(gè)部分:模型(數(shù)據(jù))、視圖、控制器(分發(fā)器)。

本文將用一個(gè)經(jīng)典的例子todoList來(lái)展開(kāi)(代碼在最后)。

js中的MVC是什么

一個(gè)事件發(fā)生的過(guò)程(通信單向流動(dòng)):

1、用戶在視圖 V 上與應(yīng)用程序交互

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

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

在js的傳統(tǒng)開(kāi)發(fā)模式中,大多基于事件驅(qū)動(dòng)的:

1、hash驅(qū)動(dòng)

2、DOM事件,用來(lái)驅(qū)動(dòng)視圖

3、模型事件(業(yè)務(wù)模型事件和數(shù)據(jù)模型事件),用來(lái)驅(qū)動(dòng)模型和模型結(jié)合

所以js中的mvc的特點(diǎn)是:單向流動(dòng)、事件驅(qū)動(dòng)

一)模型

模型存放著應(yīng)用的所有數(shù)據(jù)對(duì)象(業(yè)務(wù)數(shù)據(jù)、數(shù)據(jù)校驗(yàn)、增刪改查),比如,例子todoList中的store模型,存放每一條記錄及與之有關(guān)的邏輯。

數(shù)據(jù)是面向?qū)ο蟮?,?dāng)控制器請(qǐng)求模型讀寫(xiě)數(shù)據(jù)時(shí),模型就將數(shù)據(jù)包裝成模型實(shí)例。任何定義在這個(gè)數(shù)據(jù)模型上的函數(shù)或邏輯都可以直接被調(diào)用。在本文的例子中采用localSrorage也是類似道理的。存儲(chǔ)的Todos可以隨時(shí)被調(diào)用

模型不關(guān)心,不包含視圖和控制器的邏輯。它們應(yīng)該是互相解耦的。這里提一點(diǎn),模型與視圖的耦合,顯然是違反MVC架構(gòu)原則,但往往我們有時(shí)候卻因?yàn)闃I(yè)務(wù)關(guān)系而無(wú)法完全解耦

模型表現(xiàn)了領(lǐng)域特定的數(shù)據(jù),當(dāng)一個(gè)模型有所改變的時(shí)候,它會(huì)通知它的觀察者(視圖)。

二)視圖

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

三)控制器

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

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

Demo-todoList

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

單獨(dú)分離開(kāi)來(lái)舉例子不好講,所以在代碼中進(jìn)行注釋。首先簡(jiǎn)單理下下邊代碼的思路:

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

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

3、M層是本地存儲(chǔ)localStorage,模擬一個(gè)存儲(chǔ)數(shù)據(jù)對(duì)象的后臺(tái)模型。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>todo</title>
</head>
<body>
<header>
 <h4>待定事項(xiàng)</h4>
</header>
<main>
 <ul id="todoList"></ul>
 <input type="text" id="content">
 <button id="confirm">確認(rèn)</button>
</main>

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

 const Utils = {
  // 模擬 Modal(實(shí)體模型)
  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)) || []; // 這里一定要設(shè)置初始值為 []
  }
  }
 }

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

 let App = {
  init() {
  // this.todos 為一個(gè)存儲(chǔ)json對(duì)象的數(shù)組, 是一個(gè)實(shí)例化的數(shù)據(jù)對(duì)象,可任意調(diào)用
  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è)務(wù)邏輯層)
  bindEvent() {
  this.confirm.addEventListener('click', () => {
   // 要求模型 M 改變狀態(tài),add()函數(shù)是寫(xiě)入數(shù)據(jù)操作
   this.add()
  }, false)

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

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

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

  // render()函數(shù)作為一個(gè)訂閱者的回調(diào)函數(shù),數(shù)據(jù)的變化會(huì)反饋到模型 store
  // 換句話說(shuō):視圖通過(guò)觀察者模式,觀察模型 store,當(dāng)模型發(fā)生改變,觸發(fā)視圖更新
  render() {
  this.view()

  /**
   * 這里需要特別提一下,按照 MVC 原則這里本不應(yīng)該出現(xiàn)下面的代碼的
   * 因?yàn)闃I(yè)務(wù)邏輯關(guān)系(我本地存儲(chǔ)使用的是同一個(gè)key值,再次寫(xiě)入數(shù)據(jù)會(huì)覆蓋原來(lái)的數(shù)據(jù),),
   * 所以必須通知模型 M 保存數(shù)據(jù), V 層處理了不該它處理的邏輯,導(dǎo)致 M 與 V 耦合
   *
   * 解決辦法是:將其抽象出來(lái)編寫(xiě)一個(gè) 視圖助手 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() // 當(dāng)模型發(fā)生改變,觸發(fā)視圖更新
  },

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

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

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

mvc模式的優(yōu)點(diǎn)

mvc編程把所有精力放在數(shù)據(jù)處理,盡可能減少對(duì)網(wǎng)頁(yè)元素的處理。對(duì)于有一定數(shù)量功能的網(wǎng)頁(yè),Mvc模式下強(qiáng)制規(guī)范代碼,簡(jiǎn)化,減少重復(fù)代碼,使代碼易于擴(kuò)充。

mvc模式的弊端

1、清晰的構(gòu)架以代碼的復(fù)雜性為代價(jià), 對(duì)小項(xiàng)目反而降低開(kāi)發(fā)效率。 (如果本文的例子todoList用面條式代碼編寫(xiě),那得多簡(jiǎn)單?。。。。?br/>2、控制層和視圖層耦合,導(dǎo)致沒(méi)有真正分離和重用

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

到此,相信大家對(duì)“js中的MVC是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

js
AI