【Hybrid开发高级系列】AngularJS模块级开发模式专题

2023-10-16 12:25:07 浏览数 (3)

1 架构设计思路

1.1 App总体架构思路

        基于Hybrid开发模式的AngularJS开发,相比传统Web站点的开发模式有着很明显的差别,最主要体现在Window对象的作用域不同,在传统web开发中,所有angular module都是共享同一个Window对象,而在移动开发领域,我们更倾向于基于多WebView并存的形式来做页面内容组织,这样做最大的好处便是能尽可能多的缓存页面状态,实现类似纯原生应用的快速页面呈现体验。

        基于此论断,我们将同一个模块的页面放在同一个webview中承载,理想状态下,每一个模块均使用一个独立的webview来承载并缓存,页面呈现时基于webview缓存机制来做呈现,尽可能减少html加载时间以求达到类似原生页面的效果,因为IOS的webview加载时间较快,所以目前暂时是基于此方案来做全局路由跳转与页面状态缓存。

        而对于Android这类单个webview内存占用很大的场景,可以将webview的缓存复用与Fragment的页面状态缓存进行剥离,从而达到统一路由管理与内存可控并存的效果。

1.2 模块级开发模式设计思路

        当前APP采用Hybrid开发模式,web端采用AngularJS框架进行开发,结合AngularJS的模块解耦与路由控制特点,初步发展出结合移动端开发特点的MVC开发模式,以提高APP开发效率与交付质量。

        AngularJS的一大特点就是功能模块化设计、依赖动态注入,针对基于本地html页面的hybrid开发场景,我们尝试将业务需求基于业务流程进行模块级划分,每个业务流程作为一个独立模块单元来进行设计,模块间的页面跳转与状态同步由Native端的统一路由模块进行管理控制,模块内的页面跳转采用Angular自动的UI-Route机制处理,模块内的状态同步基于数据模块绑定来做简化处理。

        对于模块内的业务开发,结合AngularJS数据双向绑定的特点,初步采用基于MVC架构分层的开发模式来做代码开发。

2 设计分层

2.1 分层职责说明

        结合AngularJS的双向数据绑定能力,Hybrid开发中,对于Angular业务Module的开发也采用MVC架构,总体职责分配是:

 Module层

        数据模型层统一进行模块级数据对象的状态管理,数据状态的变化通过AngularJS的数据绑定能力自动更新到页面,这是数据建模产生的最大价值。

    Controller层

        页面控制器层主要职责是完成数据绑定关系映射、处理用户交互事件;当然考虑到AngularJS模块机制的特殊性,对于模块级的控制行为也可以划归为Controller层,主要包括模块内路由行为初始化、模块级生命周期事件监听与处理。

     View层

        视图呈现层在web端,对应就是html结构设计与css样式处理。

    Service层

        服务请求层,主要职责是管理与服务端交互的请求,目前主要是HTTP请求。这一层后续的重构优化空间还很大。

原生交互层

        该层用于统一管理h5与原生进行的交互,主要基于思迪框架的插件机制,在此基础上进行业务友好性封装。

        下面以定投列表模块代码为例,进行具体讲解。

2.2 数据模型层module

2.2.1 数据属性

hjMPModule.factory("dataHolder",['hjMPService',function(hjMPService) {

                  return {

                                    mpList: [],

                                    selectItem : {},

                                    dataRefsh: false,

                                    scrollTop: 0,

                                    showErrorMsg: false,

                                    errorTip: '',

2.2.2 数据操作方法

        //根据索引号查询指定定投项

        getMpItem : function(contractNo){

            for(var i = 0; i < this.mpList.length; i )

            {

                var item = this.mpList[i];

                if(item.conno == conNo)

                    return item;

            }

            return null;

        },

        removeMpItem : function(conNo)

        {

            var item = this.getMpItem(conNo);

            if(item != null)

            {

                var index = this.mpList.indexOf(item);

                this.mpList.splice(index,1);

            }

        },

        setDefaultData : function()

        {

            this.mpList = [];

            this.dataRef = false;

            this.scrollTop = 0;

            this.showErrorMsg = false;

            this.errorTip = ''

        },

        queryMyMpList : function(callback, callbackError)

        {

            var self = this;

            var hjUserId = hj.UserUtil.getUserId();

            hjMPService.queryMyMpList({

               userId: userId

            }).then(function(data) {

                if (data.mpList != null)

                    self.mpList = data.mpList;

                if(callback)

                    callback(data);

            }, function(error) {

                if(callbackError)

                {

                    callbackError(error);

                }

            });

        },

        updateMpStatus :function(status, payPassword, callback, callbackError)

        {

            var self = this;

            var promise = hjMPService.updateMpSt({

                userId: hj.UserUtil.getCmfUserId(),

                conNo: self.selectItem.conno,

                contractSt: status,

                payPassword: payPassword

            });

            promise.then(function(data) {

                self.selectItem.contractst = status;

                if (status === 'N') {

                    self.selectItem.contractst= 'N';

                } else if (status === 'P') {

                    self.selectItem.contractst= 'P';

                } else if (status === 'C') {

                    self.removeMpItem(self.selectItem.conNo);

                }

                if(callback)

                    callback(data);

            }, function(error) {

                if(callbackError)

                    callbackError(error);

            })

        }

  };

}]);

2.3 控制器层controller

2.3.1 Angular模块初始化

        模块初始化职责:

    1、模块内路由规则设定;

    2、模块内路由跳转监听;

    3、模块级生命周期事件监听;

    4、模块级页面状态维护;

2.3.2 数据对象绑定

//我的定投列表       

mpModule.controller("getMpListController",["window', 'hjMPService', 'useLoaddFact', function(scope, state, dataHolder, window, hjMPService, useLoadFact) {

    $scope.dataHolder = dataHolder;

            $scope.fVoteNoData = false;

            dataHolder.contractst = '';

2.3.3 页面字段绑定
2.3.4 交互事件处理

//修改协议状态事件

scope.modifyStatus = function(obj, type) {

    dataHolder.selectItem = $obj.item;

    dataHolder.scrollTop = scrollObj.scrollTop;

    dataHolder.dataRefsh = false;

    if($obj.item.contractst == "A" && type !== 'undo') {

        return;

    }

    if (type&& type === 'undo')

        dataHolder.contractst = 'C';

scope.parent.go("modifyStatus");

};

2.4 页面结构与呈现层html css

2.5 服务请求层Service

var hjMPModule = angular.module('hj_Fund', ['hj_Location']);

hjMPModule.factory('hjMPService',['http', 'q', 'hjServer', function(http, q, hjServer) {

    function getPromise(url, jsonObj) {

        var deferred = $q.defer();

        $http.jsonp(url, jsonObj).success(function(data) {

            if(data.resultCode === "00") {

                deferred.resolve(data);

            }else {

               deferred.reject(data.resultMsg);

            }

        }).error(function(data){

            deferred.reject("系统错误,请稍候再试!");

        });

        return deferred.promise;

}

        后续重构方向:

    1、基于业务集进行服务模块搭建;

    2、基于请求状态来做请求管理,防止重复请求;

2.6 原生交互层

2.6.1 路由引擎hj.route
2.6.2 原生视图使用hj.NativeViewUtil
2.6.3 用户信息处理hj.UserUtil

3 参考链接

$stateProvider

http://blog.csdn.net/mazhimazh/article/details/42524187

1 人点赞