【干貨理解】理解javascript中實現MVC的原理


理解javascript中的MVC

MVC模式是軟件工程中一種軟件架構模式,一般把軟件模式分為三部分,模型(Model)+視圖(View)+控制器(Controller);

模型:模型用於封裝與應用程序的業務邏輯相關的數據以及對數據處理的方法。模型有對數據直接訪問的權利。模型不依賴 "視圖" 和 "控制器", 也就是說 模型它不關心頁面如何顯示及如何被操作.

視圖:視圖層最主要的是監聽模型層上的數據改變,並且實時的更新html頁面。當然也包括一些事件的注冊或者ajax請求操作(發布事件),都是放在視圖層來完成。

控制器:控制器接收用戶的操作,最主要是訂閱視圖層的事件,然后調用模型或視圖去完成用戶的操作;比如:當頁面上觸發一個事件,控制器不輸出任何東西及對頁面做任何處理; 它只是接收請求並決定調用模型中的那個方法去處理請求, 然后再確定調用那個視圖中的方法來顯示返回的數據。

下面我們來實現一個簡單的下拉框控件,我們可以對它進行增刪操作;如下圖所示:

代碼如下:

/*
 模型用於封裝與應用程序的業務邏輯相關的數據以及對數據處理的方法。模型有對數據直接訪問的權利。
 模型不依賴 "視圖" 和 "控制器", 也就是說 模型它不關心頁面如何顯示及如何被操作.
*/
function Mode(elems) {
    // 所有元素
    this._elems = elems;
    
    // 被選中元素的索引
    this._selectedIndex = -1;

    // 增加一項
    this.itemAdd = new Event(this);

    // 刪除一項
    this.itemRemoved = new Event(this);

    this.selectedIndexChanged = new Event(this);
}

Mode.prototype = {

    constructor: 'Mode',

    // 獲取所有的項
    getItems: function(){
        return [].concat(this._elems);
    },
    // 增加一項
    addItem: function(elem) {
        this._elems.push(elem);
        this.itemAdd.notify({elem:elem});
    },
    // 刪除一項
    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});
    }
};
/*
 下面是觀察者模式類,它又叫發布---訂閱模式;它定義了對象間的一種一對多的關系,
  讓多個觀察者對象同時監聽某一個主題對象,當一個對象發生改變時,所有依賴於它的對象都將得到通知。
*/
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 < ilen; i+=1) {
            this._listeners[i](this._observer,objs);
        }
    }
};

/*
 * 視圖顯示模型數據,並觸發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;

    // 綁定模型監聽器
    this._model.itemAdd.attach(function(){
        that.rebuildList();
    });
    this._model.itemRemoved.attach(function(){
        that.rebuildList();
    });

    // 將監聽器綁定到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('<option value="'+items[key]+'">' +items[key]+ '</option>');
            }
        }
        this._model.setSelectedIndex(-1);
    }
};
/*
 控制器響應用戶操作,調用模型上的變化函數
 負責轉發請求,對請求進行處理
*/
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>

頁面初始化代碼如下:

$(function () {
    var model = new Mode(['PHP', 'JavaScript']),
      view = new View(model, {
        'list' : $('#list'), 
        'addButton' : $('#plusBtn'), 
        'delButton' : $('#minusBtn')
       }),
       controller = new Controller(model, view);        
        view.show();
}); 

代碼分析如下:

  先分下下 我們是要實現什么樣的功能; 基本功能有:一個下拉框,通過用戶輸入的操作來實現用戶增加一項及用戶選中一項后刪除一項的功能;
當然也添加了用戶切換到那一項的事件;

比如我們現在來增加一條數據的時候,在視圖層上添加監聽事件,如下代碼:
// 添加按鈕綁定事件
this._elements.addButton.click(function(e){
    that.addButtonClicked.notify();
});
然后調用觀察者類Event中的方法notify(發布一個事件) that.addButtonClicked.notify();大家都知道,觀察者模式又叫發布-訂閱模式,
讓多個觀察者對象同時監聽某一個主題對象,當某一個主題對象發生改變的時候,所有依賴它的對象都會得到通知;
因此在控制層(Controller)我們可以使用如下代碼對發布者進行監聽操作:
this._view.addButtonClicked.attach(function(){
    that.addItem();
});
之后調用自身的方法addItem();代碼如下:
addItem: function(){
    var item = window.prompt('Add item:', '');
    if (item) {
        this._model.addItem(item);
    }
}
調用模型層(model)的方法addItem();把一條數據插入到select框里面去;model(模型層)的addItem()方法代碼如下:
// 增加一項
addItem: function(elem) {
    this._elems.push(elem);
    this.itemAdd.notify({elem:elem});
},
如上代碼 增加一項后,通過 this.itemAdd 發布一個消息,然后在視圖層(View)上通過如下代碼來監聽這個消息;代碼如下:
// 綁定模型監聽器
this._model.itemAdd.attach(function(){
      that.rebuildList();
});
最后監聽到模型上(Model)的數據發生改變后,及時調用自身的方法rebuildList()去更新頁面上的數據;

模型層(Model)最主要做業務數據封裝操作。視圖層(View)主要發布事件操作及監聽模型層上的數據,如果模型層上有數據改變的時候,及時更新頁面操作,
最后顯示給頁面上來,控制層(Controller)主要監聽視圖層(View)的事件,調用模型層(Model)的方法來更新模型上的數據,模型層數據更新后,會發布
一條消息出去,最后視圖層(View)通過監聽模型層(Model)的數據變化,來更新頁面的顯示; 如上是MVC的基本流程。
MVC的優點:
1. 耦合性低:視圖層和業務層分離了,如果頁面上顯示改變的話,直接在視圖層更改即可,不用動模型層和控制層上的代碼;也就是視圖層 與 模型層和控制層
已經分離了;所以很容易改變應用層的數據層和業務規則。
2. 可維護性:分離視圖層和業務邏輯層也使得WEB應用更易於維護和修改。
MVC的缺點:
個人覺得適合於大型項目,對於中小型項目並不適合,因為要實現一個簡單的增刪改操作,只需要一點點JS代碼,但是MVC模式代碼量明顯增加了。
對於學習成本也就提高了,當然如果使用一些封裝好的MVC庫或者框架就好了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM