搜尋

首頁  >  問答  >  主體

mvc - 前端程式碼怎樣處理使用者操作跟 Model 的一對多關係?

場景是這樣的:

這樣一個操作, 需要同時依賴很多個 Model, 因此這些程式碼不會寫在某一個 Model 裡邊.
有可能是例如 Backbone, 寫在 ViewController 裡邊... 但是這樣程式碼復用不好, 而且 View 會變亂.
我目前採取的方案是用單獨一個文件去收集大部分的 Model 操作, 不過問題是, 這個文件會不斷變大變亂.
所以這樣的問題該如何解決?

延伸的問題是, 怎麼整理這部分程式碼?
例如我用 React 的 Flux 方案, 盡量將流程理清楚, 就發現這部分程式碼不知道放在哪裡合適..
Flux 將使用者操作轉換為 Actions, Store 透過 Dispatcher 監聽這些 Actions,
一個 Actions 對應多個 Store 的時候... 問題就來了:
我該用多個 Actions 分別對應 Store, 還是一個 Action 由多個 Store 來監聽?

PHP中文网PHP中文网2773 天前487

全部回覆(4)我來回復

  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-05-16 17:08:22

    用戶點擊按鈕本質上跟用戶透過URL訪問一樣,都是一種‘輸入’,所以問題和處理機制都是一樣的:在view層代碼裡監聽‘輸入’,處理一些view層(比如按鈕組件的toggle、URL的矯正)內部的狀態變化,生成/提取出純粹的、抽象層級更高的(跟view組件或URL細節無關)數據/訊息,用某種事件機制廣播出去,之後就跟自己沒關係了,接下來如果有controller層的話,在這部分的程式碼裡監聽這些事件,調用相應model物件的方法(其中可能封裝了model物件自己之間的依賴關係和調用,但這裡的一對多複雜性不會暴露到外面去),同時也監聽某些model物件的狀態變化,呼叫對應view物件的方法(或是重新渲染Virtual DOM)。所有東西綁定完成。

    像我平常用NervJS(model) + DermJS(view)+ URLKit(route) 這樣的搭配,NervJS和DermJS物件都有自帶的事件方法,此外也可以在view/model物件初始化時傳入統一的bus事件對象。

    你寫一個UI component的時候當然不會希望它依賴特定的model,寫一個model組件的時候,也不會希望它依賴特定UI,所以一對多之類的綁定是在另一個地方(專門的業務邏輯程式碼)完成的,view物件和model物件不需要也不應該知道對方有幾個、是哪些,所以也不可能『多個Actions 分別對應Store』。

    至於『單獨一個檔案』、『不斷變大變亂』的問題,跟設定路由的檔案也是一回事,可以參考相關經驗。

    回覆
    0
  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-05-16 17:08:22

    flux裡,如果需要一個動作對應多個Store,其實也是很好解決的。
    在Store裡面register回呼的時候,可以都對這個動作進行相應就可以了,還可以透過waitFor來改變對應的順序。

    如果擔心程式碼變亂的話,可以再單獨寫一個constants文件,定義好觸發的事件名稱就可以了。

    舉例:

    點選一個按鈕,觸發send事件,会更新两个Store分别是StoreAStoreB。可以写一个constants.js,先定義事件名稱:

    constants:

    module.exports = {
        "ActionTypes": {
            "SEND": "SEND"
        }
    };
    

    然後在兩個Store裡面分別註冊回調:

    StoreA:

    var AppDispatcher = require('path/to/disp'),
        constants = require('path/to/constants');
    
    StoreA.dispatchToken = AppDispatcher.register(function(payload) {
        var action = payload.action;
        if (action.type === constants.ActionTypes.SEND) {
            // callback A
        };
    });
    

    StoreB:

    var AppDispatcher = require('path/to/disp'),
        constants = require('path/to/constants');
    
    StoreB.dispatchToken = AppDispatcher.register(function(payload) {
        var action = payload.action;
        if (action.type === constants.ActionTypes.SEND) {
            // callback B
        };
    });
    

    在觸發點擊事件的時候,在Action中触发Disp的这个事件,就会顺序执行在StoreAStoreB中註冊的回調了:)

    回覆
    0
  • PHP中文网

    PHP中文网2017-05-16 17:08:22

    當這種情況出現時,我通常想到的是,可不可以在他們中間加上一層了。

    回覆
    0
  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-05-16 17:08:22

    如果沒看過,或是看過但忘了,這是一篇值得讀的文章:

    Patterns For Large-Scale JavaScript Application Architecture

    簡單而言,你需要有些「約定俗成」的東西,讓view和model無需相互依賴(不管是1:1的依賴,還是1:N的依賴)。

    用簡單的event和observer pattern也可以,如果業務邏輯很複雜,用mediator完成模組間的通訊和同步。

    PS:理想的情況是,你的每個模組都只知道自己(觸發什麼事件,聆聽什麼事件),除此之外都不管,更不會知道對方的instance,或者mediator的instance。

    回覆
    0
  • 取消回覆