资讯专栏INFORMATION COLUMN

mv**中,用数据层解决多个view对应不同model的问题

tommego / 2338人阅读

摘要:回调使用事件可以支持多个成功后的回调。实际生产中,如果模块的数据层管理使用场景只有一个,也不需要在操作中做相关操作。一般只需要实例化成单例提供管理数据的相关事件到不同的组件。

说明

博文中code例子是基于nej编写,如果你没使用过nej,也不会妨碍你理解代码。

适用场景

实际开发中常遇到不同model对应多个view。用户通过 View 层来交互,View 有时需要根据用户的数据更新 Model。还有时 Model 需要更新其他的 Model,即一个model改变,触发一连串的view变化。

解决办法

这种情况,开发者可以将所有对数据的操作独立成一个数据层模块,集中管理数据相关的action。
nej这种机制的例子(不讨论缓存),delete操作作为理解例子util/cache/list.js
cache组件提供一个对外的action -- _$deleteItem

/**
 * 删除列表项
 *
 * 脚本举例
 * ```javascript
 * _cc._$deleteItem({
 *     key: "123"
 * });
 * ```
 *
 * @method   module:util/cache/list._$$CacheList#_$deleteItem
 * @param    {Object} arg0 - 配置信息
 * @property {String} key  - 列表标识
 * @property {String} id   - 列表项标识
 * @property {Object} data - 列表项数据信息
 * @property {Object} ext  - 需要回传的数据信息
 * @return   {Void}
 */
_pro._$deleteItem = function(_options){
    _options = _u._$merge({},_options);
    _options.onload = this.__deleteItem._$bind(this,_options);
    this._$dispatchEvent("dodeleteitem",_options);
};

通过cache组件实例._$batEvent("dodeleteitem", function(){});来发送ajax请求。请求所要options由外部组件调用cache组件action时传入。一般只需要传入参数。onload回调使用dispatch事件(可以支持多个成功后的回调)。

/**
 * 删除列表项回调
 *
 * @protected
 * @method module:util/cache/list._$$CacheList#__deleteItem
 * @param  {Object}  arg0 - 请求信息
 * @param  {Boolean} arg1 - 是否删除成功
 * @return {Void}
 */
_pro.__deleteItem = function(_options,_isok){
    // 列表的例子中可以做一下cache相关的操作
    var _item,
        _key = _options.key;
    // sync memory
    if (!!_isok){
        var _id = _options.id;
        _item = this._$getItemInCache(_id)||null;
        this.__doRemoveItemFromList(_key,_id);
    }
    // callback
    var _event = {
        key:_key,
        data:_item,
        action:"delete",
        ext:_options.ext
    };
    this._$dispatchEvent("onitemdelete",_event);
    return _event;
};

通过cache组件实例._$batEvent("onitemdelete", function(){}); 可以实现删除成功之后的回调。不同views组件可以独立绑定事件回调,这样代码解耦。一个view不需要的时候,不需要改代码。

每个cache组件都是一个单例实例。保证了在每个不同的功能组件(view)中用到的是同一个。
每一类list cache组件都可以有自己的不同的crud,例如bookList.js

// $$CacheList  == cache/list.js
var bookList = _t._$$CacheList._$allocate({
    id: "abc",
    doloadlist: function (_options) {
        // 从服务器加载列表
        _j._$request(
            "/api/list", {
                data: _options.data,
                onload: function (_list) {
                    _options.onload(_list);
                }
            }
        );
    },
    dodeleteitem: function (_options) {  _options由调用cache.action处传入
        // 从服务器删除数据项
        _j._$request(
            "/api/delete", {
                data: _options.data,
                onload: function (_item) {
                    _options.onload(_item);
                }
            }
        );
    }
});
return bookList;

nej对每一个list cache组件又抽象了一个基类cache/abstract.js
bookList.js继承abstract.js,按照api实现指定接口,返回list cache组件实例
list的数据层管理,可以抽象出通用的api,crud。所以nej把这种场景抽象成list.js。实际生产中,如果模块的数据层管理使用场景只有一个,也不需要在crud操作中做cache相关操作。一般只需要实例化成单例提供管理数据的action,dispatch相关事件到不同的views组件。

// custom.js
_p._$$Custom = _k._$klass(); 
_pro = _p._$$Custom._$extend(_t._$$EventTarget);
_pro.__doSendRequest = function(key,options){
    var conf = config[key];
    // onload event
    var onload = function(result){
        if (!result||(""+result.code).indexOf("2")!==0){
            onerror.call(this,result);
            return;
        }
        // callback
        var callback = options.onload||conf.onload||"success";
        if (u._$isFunction(callback)){
            callback.call(this,result.result);
        }else if(u._$isString(callback)){
            // dispatch在不同view组件中,绑定的事件
            this._$dispatchEvent(callback,result.result);
        }
    };
    // options其他属性可以由调用action _$checkUserName处传入
    //data
    //type:"json",
    //method:"POST",
    options.onload = onload._$bind(this);
    request(options)
};
_pro._$checkUserName = function(options){
    this.__doSendRequest("checkUserName", options);
};
return _p._$$Custom._$allocate({});

//在view组件中使用
// component1 
define(["custom.js"], function(c){
    c._$batEvent("onusernamecheckok", function(){
        console.log("表单中username相关验证显示通过的样式");
    });
    // checkUserName DOM click事件
    var onCheck = function(
        c._$checkUserName({
            data: {xx: "王大锤"},
            onload: "onusernamecheckok"
        });
    );
});

// component2
define(["custom.js"], function(c){
    c._$batEvent("onusernamecheckok", function(){
        console.log("修改topbar的userName");
    });
});

如今mv**库一片火热的今天,也会也到多个view对应一个model的场景,facebook提出了一种解决方案单向数据流,单向数据流——就一个方向——当你需要插入新的数据,流完全重新开始。他们把这种架构称为Flux。

Flux的大致流程如下

通过这样设计,View的功能就会变得纯粹许多。它不需要关心组件的状态和数据的操作,只需要把交到它们手中的数据渲染格式化成用户能够理解的输出(HTML)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86083.html

相关文章

  • 关于框架

    摘要:事件订阅发布者模式什么是读音类似于是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,采用自底向上增量开发的设计。 MVC && MVVM 前端框架前端 MV*框架的意义 被误解的MVC和被神化的MVVM Vue.js新手入门指南 单页应用SPA的路由 单页面应用的路由问题 本文是在自己总结时,看了许多篇文章有了些体会,然后把我认为有意义的摘抄下来,文中很大部分摘录以上...

    Richard_Gao 评论0 收藏0
  • 切图崽自我修养-[MVVM] Js MV*模式浅谈

    摘要:在没有环境下对进行单元测试的时候,应用逻辑正确性是无法验证的更新的时候,无法对的更新操作进行断言。对是通过接口进行,在对进行不依赖环境的单元测试的时候。这里根据上面的例子给出了的单元测试样例。年微软工程师在自己的博客上首次公布了模式。 前言 做客户端开发、前端开发对MVC、MVP、MVVM这些名词不了解也应该大致听过,都是为了解决图形界面应用程序复杂性管理问题而产生的应用架构模式。网上...

    bluesky 评论0 收藏0
  • 切图崽自我修养-[MVVM] Js MV*模式浅谈

    摘要:在没有环境下对进行单元测试的时候,应用逻辑正确性是无法验证的更新的时候,无法对的更新操作进行断言。对是通过接口进行,在对进行不依赖环境的单元测试的时候。这里根据上面的例子给出了的单元测试样例。年微软工程师在自己的博客上首次公布了模式。 前言 做客户端开发、前端开发对MVC、MVP、MVVM这些名词不了解也应该大致听过,都是为了解决图形界面应用程序复杂性管理问题而产生的应用架构模式。网上...

    shleyZ 评论0 收藏0

发表评论

0条评论

tommego

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<