首页  >  问答  >  正文

mvc - 前端代码怎样处理用户操作跟 Model 的一对多关系?

场景是这样的:

这样一个操作, 需要同时依赖很多个 Model, 因此这些代码不会写在某一个 Model 里边.
有可能是比如 Backbone, 写在 ViewController 里边... 但是这样代码复用不好, 而且 View 会变乱.
我目前采取的方案是用单独一个文件去收集大部分的 Model 操作, 不过问题是, 这个文件会不断变大变乱.
所以这样的问题应该如何解决?

延伸的问题是, 怎样整理这部分代码?
比如我用 React 的 Flux 方案, 尽量将流程理清楚, 就发现这部分代码不知道放在哪里合适..
Flux 将用户操作转化为 Actions, Store 通过 Dispatcher 监听这些 Actions,
一个 Actions 对应多个 Store 的时候... 问题就来了:
我是应该用多个 Actions 分别对应 Store, 还是一个 Action 由多个 Store 来监听?

PHP中文网PHP中文网2691 天前418

全部回复(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
  • 取消回复