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

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

场景是这样的:

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

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


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中注册的回调了:)


当这种情况出现时,我通常想到的是,可不可以在在他们中间加上一层了。


如果你没看过,或者看过但忘了,这是篇值得读的文章:

Patterns For Large-Scale JavaScript Application Architecture

简单而言,你需要有些“约定俗成”的东西,让view和model无需相互依赖(不管是1:1的依赖,还是1:N的依赖)。

用简单的event和observer pattern也可以,如果业务逻辑很复杂,用mediator完成模块间的通信和同步。

PS:理想的情况是,你的每个模块都只知道自己(触发什么事件,聆听什么事件),除此之外都不管,更不会知道对方的instance,或者mediator的instance。


用户点击按钮本质上跟用户通过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』。

至于『单独一个文件』、『不断变大变乱』的问题,跟配置路由的文件也是一回事,可以参考相关经验。

【热门文章】
【热门文章】