Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Understanding the MVC,MVP,MVVM in JavaScript

Understanding the MVC,MVP,MVVM in JavaScript

JSDC 2013 Slides

大澤木小鐵

May 19, 2013
Tweet

More Decks by 大澤木小鐵

Other Decks in Technology

Transcript

  1. UNDERSTANDING THE
    MVC
    MVP
    MVVM
    IN JAVASCRIPT

    View Slide

  2. View Slide

  3. 咦?默念?

    View Slide

  4. Who am I ?
    I am Iron Man

    View Slide

  5. Who am I ?
    I am Iron Man
    閃到腰的

    View Slide

  6. Jace Ju
    ⼤大澤⽉⽊木⼩小鐵

    View Slide

  7. ⺫⽬目前正在領
    微博的薪⽔水

    View Slide

  8. 我不是前端工程師...

    View Slide

  9. 我不是前端工程師...
    我也不是社工...

    View Slide

  10. 我不是前端工程師...
    我也不是社工...
    我只是個打雜的...

    View Slide

  11. 我不是前端工程師...
    我也不是社工...
    我只是個打雜的...
    System, DBA, Backend...
    HTML, CSS, JavaScript...
    我都只會一點點... Orz

    View Slide

  12. 雖然我是這次
    講師群裡最弱的

    View Slide

  13. 雖然我是這次
    講師群裡最弱的
    但我有 GitHub
    https://github.com/jaceju

    View Slide

  14. 不過我喜歡分享
    自己學到的給大家
    然後也從大家
    那邊學到很棒的東西
    ^ ^

    View Slide

  15. 20 年前...

    View Slide

  16. 20 年前...
    駭客正夯

    View Slide

  17. 20 年前...
    駭客正夯
    GUI (圖形化操作介面)

    View Slide

  18. 視覺控制項與資料整合
    強化使⽤用者對資料的印象
    事件驅動
    配合 Framework / IDE
    GUI

    View Slide

  19. 常常會在事件處理⽅方法裡
    包含了資料運算邏輯
    每個元件之間的互動
    都放在⼀一個⽅方法裡
    問題

    View Slide

  20. MVC / MVP / MVVM
    就是要解決這些問題

    View Slide

  21. 瞭解 MVC / MVP / MVVM
    的基本原理
    JavaScript 如何實作它們
    所以今天...

    View Slide

  22. MV*

    View Slide

  23. MV* ⺫⽬目的
    視覺邏輯
    流程邏輯 資料運算邏輯

    View Slide

  24. 從資料運算邏輯中分離視覺邏輯
    MV* ⺫⽬目的
    視覺邏輯
    流程邏輯 資料運算邏輯

    View Slide

  25. 從資料運算邏輯中分離視覺邏輯
    從視覺邏輯中分離流程邏輯
    MV* ⺫⽬目的
    視覺邏輯
    流程邏輯 資料運算邏輯

    View Slide

  26. 分離關注點
    團隊合作
    便於測試
    推卸責任

    View Slide

  27. 團隊合作
    便於測試
    推卸責任
    分離關注點
    釐清問題點

    View Slide

  28. Example
    0px
    + -
    span#num
    button#increase button#decrease

    View Slide

  29. Code
    http://jsfiddle.net/EWbxg/

    View Slide

  30. Model
    View
    &

    View Slide

  31. var myapp = {};
    myapp.Model = function () {
    var val = 0;
    this.add = function (v) {
    if (val < 100) val += v;
    };
    this.sub = function (v) {
    if (val > 0) val -= v;
    };
    this.getVal = function () {
    return val;
    };
    };
    Model
    資料的狀態

    View Slide

  32. var myapp = {};
    myapp.Model = function () {
    var val = 0;
    this.add = function (v) {
    if (val < 100) val += v;
    };
    this.sub = function (v) {
    if (val > 0) val -= v;
    };
    this.getVal = function () {
    return val;
    };
    };
    Model
    操作內部狀態的⾏行為

    View Slide

  33. myapp.View = function () {
    var $num = $('#num');
    var $incBtn = $('#increase');
    var $decBtn = $('#decrease');
    this.render = function (model) {
    $num.text(model.getVal() + 'px');
    };
    };
    View
    管理視覺元件

    View Slide

  34. View
    myapp.View = function () {
    var $num = $('#num');
    var $incBtn = $('#increase');
    var $decBtn = $('#decrease');
    this.render = function (model) {
    $num.text(model.getVal() + 'px');
    };
    };
    呈現資料

    View Slide

  35. MVC

    View Slide

  36. 由 Xerox PARC 提出
    MVC 簡史
    http://huoding.com/2011/05/02/64
    MVC 簡介

    View Slide

  37. View 觀察 Model
    Controller 負責派送 Request
    並控制 Model 的狀態
    使⽤用者接觸的對象是
    Controller
    MVC 架構
    看報紙才知道

    View Slide

  38. View
    Controller
    Model

    View Slide

  39. (箭頭⽅方向表⽰示擁有該物件參考)
    View
    Controller
    Model
    Controller 初始化
    Model 與 View

    View Slide

  40. View
    Controller
    Model
    View 向 Model 註冊

    View Slide

  41. View
    Controller
    Model
    使⽤用者看到 View
    的初始輸出

    View Slide

  42. View
    Controller
    Model
    使⽤用者向 Controller
    發出請求

    View Slide

  43. View
    Controller
    Model
    Controller 改變
    Model 狀態
    Model 再次
    通知 View

    View Slide

  44. View
    Controller
    Model
    使⽤用者看到 View
    改變了輸出

    View Slide

  45. Code
    http://jsfiddle.net/uVBvq/

    View Slide

  46. myapp.Model = function () {
    // ...
    var views = [];
    this.register = function (view) {
    views.push(view);
    }
    var self = this;
    this.notify = function () {
    for (var i = 0;
    i < views.length; i++) {
    views[i].render(self);
    }
    };
    };
    Model
    Model 擁有 View 的參考

    View Slide

  47. myapp.Model = function () {
    // ...
    var views = [];
    this.register = function (view) {
    views.push(view);
    }
    var self = this;
    this.notify = function () {
    for (var i = 0;
    i < views.length; i++) {
    views[i].render(self);
    }
    };
    };
    Model
    Model 有變化時通知 View 更新

    View Slide

  48. View
    myapp.View = function (controller) {
    // ...
    $incBtn.click(controller.increase);
    $decBtn.click(controller.decrease);
    };
    引⽤用 Controller 參考

    View Slide

  49. myapp.View = function (controller) {
    // ...
    $incBtn.click(controller.increase);
    $decBtn.click(controller.decrease);
    };
    View
    將事件綁定在
    Controller 的 Action

    View Slide

  50. myapp.Controller = function () {
    var model = null;
    var view = null;
    this.init = function () {
    model = new myapp.Model();
    view = new myapp.View(this);
    model.register(view);
    model.notify();
    };
    };
    Controller
    Controller 初始化
    Model 與 View

    View Slide

  51. myapp.Controller = function () {
    var model = null;
    var view = null;
    this.init = function () {
    model = new myapp.Model();
    view = new myapp.View(this);
    model.register(view);
    model.notify();
    };
    };
    Controller
    View 向 Model
    註冊⾃自⼰己

    View Slide

  52. myapp.Controller = function () {
    // ...
    this.increase = function () {
    model.add(1);
    model.notify();
    };
    this.decrease = function () {
    model.sub(1);
    model.notify();
    };
    };
    Controller
    Controller 負責控制 Model

    View Slide

  53. (function () {
    var controller = new myapp.Controller();
    controller.init();
    })();
    Run
    外界只接觸到 Controller

    View Slide

  54. Model 不應該擁有 View 的參考
    View 不容易測試
    缺點

    View Slide

  55. MVP
    叫我嗎?

    View Slide

  56. 由 IBM 提出
    Microsoft ASP.Net
    WebForms
    MVP 簡介

    View Slide

  57. 使⽤用者接觸的對象是 View
    Presenter 取代 Controller
    派送的⾓角⾊色由 View 來扮演
    MVP 結構

    View Slide

  58. Supervising Controller
    Passive View
    MVP 類型

    View Slide

  59. Passive View
    View 和 Model 不需要知道對⽅方
    Presenter 的⼯工作量⽐比較⼤大
    整體的可測試⽐比較好

    View Slide

  60. View
    Presenter
    Model

    View Slide

  61. View
    Model
    Presenter
    使⽤用者看到 View
    的初始輸出
    View 初始化 Presenter

    View Slide

  62. View
    Model
    Presenter
    Presenter 初始化 Model

    View Slide

  63. View
    Model
    Presenter
    View 委派 Presenter 來
    處理使⽤用者的請求
    使⽤用者透過 View
    來發出請求

    View Slide

  64. Persenter 改變
    並獲取 Model 狀態
    View
    Model
    Presenter

    View Slide

  65. 使⽤用者看到 View
    改變了輸出
    View
    Model
    Presenter
    Presenter
    將 Model 的狀態
    更新到 View 上⾯面

    View Slide

  66. 簡單來說
    要在發生某個事件後
    我們才會知道
    總統是隻水母

    View Slide

  67. Code
    http://jsfiddle.net/tgHra/

    View Slide

  68. myapp.Model = function () {
    var val = 0;
    this.add = function (v) {
    if (val < 100) val += v;
    };
    this.sub = function (v) {
    if (val > 0) val -= v;
    };
    this.getVal = function () {
    return val;
    };
    };
    Model
    不需要觀察者模式

    View Slide

  69. myapp.Presenter = function (view) {
    var _model = new myapp.Model();
    var _view = view;
    _view.render(_model.getVal());
    this.increase = function () {
    _model.add(1);
    _view.render(_model.getVal());
    };
    this.decrease = function () {
    _model.sub(1);
    _view.render(_model.getVal());
    };
    };
    Presenter
    Presenter 將
    Model 內容
    傳遞給 View

    View Slide

  70. myapp.View = function () {
    // ...
    this.init = function () {
    var presenter = new myapp.Presenter(this);
    $incBtn.click(presenter.increase);
    $decBtn.click(presenter.decrease);
    };
    }
    View
    View 將請求委派給 Presenter

    View Slide

  71. (function () {
    var view = new myapp.View();
    view.init();
    })();
    Run
    外界只接觸到 View

    View Slide

  72. 與 MVC 差異
    適合維持狀態
    View 與 Model 之間解耦

    View Slide

  73. 與 MVC 差異
    適合維持狀態
    View 與 Model 之間解耦

    View Slide

  74. MVVM

    View Slide

  75. 由 Microsoft 提出
    Microsoft WPF
    Knockout.js
    http://blog.darkthread.net/
    post-2012–05–09-knockout-js-intro.aspx
    MVVM 簡介

    View Slide

  76. ViewModel :
    將資料轉換成視覺元件可⽤用的狀態
    View : 包含 bind 邏輯的樣版
    Model : 跟資料來源溝通⽤用
    MVVM 架構

    View Slide

  77. ViewModel ⼀一有變化就更新 View
    View ⼀一有輸⼊入值就更新 ViewModel
    Data-Binding 由 Framework 來處理
    不必⾃自⼰己找元素
    Two-way
    Data Binding

    View Slide

  78. Code
    http://jsfiddle.net/fVAcE/

    View Slide



  79. +
    -
    View (knockout.js)
    View (Template) 透過 HTML
    屬性來與 ViewModel 結合

    View Slide

  80. myapp.ViewModel = function () {
    var model = new myapp.Model();
    this.num = ko.observable(model.getVal());
    this.val = ko.computed(function() {
    return this.num() + 'px';
    }, this);
    };
    ViewModel
    View 利⽤用觀察者模式
    將 ViewModel 結合起來

    View Slide

  81. myapp.ViewModel = function () {
    // ...
    this.increase = function () {
    model.add(1);
    this.num(model.getVal());
    };
    this.decrease = function () {
    model.sub(1);
    this.num(model.getVal());
    };
    };
    ko.applyBindings(new myapp.ViewModel());
    ViewModel
    ViewModel 操作 Model
    並將資料 binding 到 View 元素上

    View Slide

  82. myapp.ViewModel = function () {
    // ...
    this.increase = function () {
    model.add(1);
    this.num(model.getVal());
    };
    this.decrease = function () {
    model.sub(1);
    this.num(model.getVal());
    };
    };
    ko.applyBindings(new myapp.ViewModel());
    ViewModel
    透過 Framework 結合
    View 與 ViewModel

    View Slide

  83. 需要隨時監控 View 的狀態
    效能會受到影響
    效能掌握在 Framework ⼿手上
    Data-Binding 的錯誤要在
    Runtime 時才能發現
    MVVM 缺點

    View Slide

  84. EVENT

    View Slide

  85. ⽤用事件代替引⽤用,
    解耦物件之間的關係
    維繫事件與 callbacks
    射後不理
    Event 概念

    View Slide

  86. callback
    Object Event
    callback
    callback
    註冊事件對應的
    callback
    (on / bind)

    View Slide

  87. Object Event
    物件觸發事件
    (trigger)
    callback
    callback
    callback

    View Slide

  88. Object Event
    Event 呼叫事件
    對應的 callback
    callback
    callback
    callback

    View Slide

  89. Code
    http://jsfiddle.net/pm3xr/
    從 Backbone.js
    抽出來簡化

    View Slide

  90. var Event = {
    _events: {},
    on: function(name, callback, context) {
    ! this._events || (this._events = {});
    ! var events = this._events[name]
    ! !
    ! || (this._events[name] = []);
    ! events.push({
    ! ! callback: callback,
    ! ! ctx: context
    ! });
    }
    };
    Event.on
    將 callback 及 context
    加到事件的庫裡

    View Slide

  91. Event.trigger
    var Event = {
    // ...
    trigger: function(name) {
    !
    var events = this._events[name];
    !
    for (var i = 0; i < events.length; i++) {
    !
    ! (ev = events[i]).callback.call(ev.ctx);
    !
    }
    }
    };
    將事件對應的 callback
    ⼀一⼀一找出來執⾏行

    View Slide

  92. Event.on('event1', function () {
    ! alert('callback 1');
    }, this);
    Event.on('event1', function () {
    ! alert('callback 2');
    }, this);
    Event.on('event2', function () {
    ! alert('callback 3');
    }, this);
    Event.trigger('event1');
    Event.trigger('event2');
    Event Demo
    事件綁定 callback

    View Slide

  93. Event.on('event1', function () {
    ! alert('callback 1');
    }, this);
    Event.on('event1', function () {
    ! alert('callback 2');
    }, this);
    Event.on('event2', function () {
    ! alert('callback 3');
    }, this);
    Event.trigger('event1');
    Event.trigger('event2');
    Event Demo
    觸發事件

    View Slide

  94. 取代了觀察者模式
    Model, View 透過 Event 溝通
    Controller, Presenter,
    ViewModel 可以更靈活
    隱藏在 Framework 裡
    Event + MV*

    View Slide

  95. Conclusion

    View Slide

  96. 觀看的⾓角度與實作的⽅方式
    邏輯分離
    模組化
    各位還是⽤用 Framework 吧
    Points

    View Slide

  97. 前端工程...
    會跟著各位一起成長的

    View Slide

  98. YOU
    THANK

    View Slide