SPA预研

简介

演  讲 者   :

10年西南大学本科毕业,后从事2年java开发, 12年专职前端开发,13年进入腾讯,

现职于FIT 金融市场部前端开发工程师。

http://www.lowinwu.com

 lowinwu(吴祥 )

博       客   : 

个人简介  :

SPA预研

大纲

1、何为单页面

3、构成

2、业界方案

4、自研框架

6、优缺点

7、疑问解答

5、案例

SPA预研

开发区别

体验区别

1、页面前进,

资源重复下载、执行

2、页面回退,

资源重复下载、执行

1、配置环境

2、模板片段引入

标题,路由执行方法...

js&html结合

3、减少cgi数量

 模板页面,微信授权信息获取

<?cs include:PARSE_PATH("/hybrid/mch/inc/js/dust.html") ?>
<?cs include:PARSE_PATH("/hybrid/mch/inc/js/hkwallet_config.html") ?>
<script type="text/javascript">
	var USER_FLAG = "<?cs var:user_flag ?>";
	var PAY_PARAM = {
		bind_type : "<?cs var:bind_type ?>" || 1,
		user_state : "<?cs var:user_state ?>" || 1,
		ticket_flag : "<?cs var:ticket_flag ?>",
		ticket : "<?cs var:ticket ?>"
	}
	var G_NOT_NEED_BASE = 1;
    dust.use(["/res/scripts/app/hkwallet/ewallet_global.js","/res/scripts/app/hkwallet/ewallet_add_cardnum.js"],function(app,index){
        app.init(function(){
            index.init();
        });
    })

</script>
</body>
</html>

SPA预研

业界方案

SPA预研

业界方案(1)-pjax

ajax+pushstate

http://userbag.co.uk/demo/pjax/

https://github.com/welefen/pjax

SPA预研

业界方案(1)-pjax

ajax+pushstate

SPA预研

业界方案(1)-pjax

ajax+pushstate

1、不支持刷新功能,需接合cgi

缺点

2、依赖jquery  

 3、不支持hash方式,兼容性差

SPA预研

业界方案(2)-angular

requirejs + angular + angular-route

http://beletsky.net/2013/11/using-angular-dot-js-with-require-dot-js.html

define(['angular', 'require', 'angular-route'], function (angular, require) {

    var app = angular.module('webapp', [
        'ngRoute'
    ]);
    app.config(['$routeProvider', '$controllerProvider',
        function($routeProvider, $controllerProvider) {
            $routeProvider.
                when('/module1', {
                    templateUrl: 'module1/tpl.html',
                    controller: 'module1Controller',
                    resolve: {
                        keyName: function ($q) {
                            var deferred = $q.defer();
                            require(['module1/module1.js'], function (controller) {
                                $controllerProvider.register('module1Controller', controller);      //由于是动态加载的controller,所以要先注册,再使用
                                deferred.resolve();
                            });
                            return deferred.promise;
                        }
                    }
                }).
                otherwise({
                    redirectTo: '/module1'     
                });
        }]);

    return app;
});
define(['angular'], function (angular) {

    //angular会自动根据controller函数的参数名,导入相应的服务returnfunction($scope, $http, $interval){
        $scope.info = 'kenko';      //向view/模版注入数据//模拟请求cgi获取数据,数据返回后,自动修改界面,不需要啰嗦的$('#xxx').html(xxx)
        $http.get('module2/tpl.html').success(function(data) {
            $scope.info = 'vivi';
        });
    };
});

SPA预研

业界方案(2)-angular

requirejs + angular + angular-route

SPA预研

业界方案(2)-angular

requirejs + angular + angular-route

1、压缩包78K

缺点

2、开发逻辑复杂

3、语法复杂

SPA预研

业界方案(3)-backbone

http://coenraets.org/blog/2013/06/building-modular-web-applications-with-backbone-js-and-requirejs-sample-app/

Modularized Model

define(function (require) {
    "use strict";
    var $           = require('jquery'),
        Backbone    = require('backbone'),

        Employee = Backbone.Model.extend({

            urlRoot: "http://localhost:3000/employees",

            initialize: function () {
                this.reports = new EmployeeCollection();
                this.reports.url = this.urlRoot + "/" + this.id + "/reports";
            }
        }),
        EmployeeCollection = Backbone.Collection.extend({

            model: Employee,

            url: "http://localhost:3000/employees"

        });
    return {
        Employee: Employee,
        EmployeeCollection: EmployeeCollection
    };

});
Modularized Router
define(function (require) { 
    var $           = require('jquery'),
        Backbone    = require('backbone'),
        $content = $("#content");
    return Backbone.Router.extend({
        routes: {
            "":                 "home",
            "employees/:id":    "employee"
        },
        home: function () {
            require(["app/views/Home"], function (HomeView) {
                var view = new HomeView({el: $content});
                view.render();
            });
        },
        employee: function (id) {
            require(["app/views/Employee", "app/models"], function (EmployeeView, models) {
                var employee = new models.Employee({id: id});
                employee.fetch({
                    success: function (data) {
                        var view = new EmployeeView({model: data, el: $content});
                        view.render();
                    }
                });
            });
        }
 
    });
 
});
Modularized View
define(function (require) {
    "use strict";
    var $           = require('jquery'),
        _           = require('underscore'),
        Backbone    = require('backbone'),
        tpl         = require('text!tpl/Employee.html'),
        template = _.template(tpl);
    return Backbone.View.extend({
        render: function () {
            this.$el.html(template());
            return this;
        }
    });
});

SPA预研

业界方案(3)-backbone

SPA预研

业界方案(3)-backbone

1、MVC死板 

缺点

2、开发流程复杂 

SPA预研

构 成

路由管理

代码组织

注册路由,查找路由,启动路由

视图注入,title更换,主入口

SPA预研

自研框架

SPA预研

面临问题

URL监听

缓存策略

首屏保障

代码隔离

切屏方案

......

穿透事件

跨域方案

性能优化

SPA预研

措  施

1、路由注册与监控

2、功能模块化加载与管理

SPA预研

路由监控

1、注册路由

2、ajax与tap/click事件

3、监控路由变化

刷新&第三方跳转

重新包装&写路由

onhashchange

SPA预研

多模块加载&管理

描述:复杂交互中,

按需加载代码隔离,模块注入...

如何解决?

SPA预研

方案1:html与js全注入首页

消耗首屏,无效加载,js污染

方案2:动态加载js--require("xx.js")

减少js消耗首屏时间&无效加载

<div class="container">
    <?cs include:PARSE_PATH("/hybrid/mch/weixin/transfer_hk/mod/guide.shtml") ?> 
    <!--表单[[-->
    <div class="main hide js-send"></div>
    <!--表单]]-->
    <?cs include:PARSE_PATH("/hybrid/mch/weixin/transfer_hk/mod/input_confirm.shtml") ?>
</div>
  dust.use(["/res/scripts/app/hkwallet/ewallet_global.js","/res/scripts/app/hkwallet/ewallet_add_cardnum.js"],function(app,index){
        app.init(function(){
            index.init();
        });
    })
regRouters:function(){//注册路由
   $.SPA.r({
       id: 'main_content',//挂载点
       type:'index',//设置为首页
       animate: '',                          //入场动画效果
       script:'/res/scripts/app/transfer_hk/record.js'
    });
},
init:fucntion(){
  this.regRouter();//注册路由
  $.SPA.startRun();//启动监听
}

多模块管理

SPA预研

方案3:业务js中嵌入html

代码强偶合,不利于维护

<div class="container">
    <?cs include:PARSE_PATH("/hybrid/mch/weixin/transfer_hk/mod/guide.shtml") ?> 
    <!--表单[[-->
    <div class="main hide js-send"></div>
    <!--表单]]-->
    <?cs include:PARSE_PATH("/hybrid/mch/weixin/transfer_hk/mod/input_confirm.shtml") ?>
</div>
define(function(require,exports,module){
   var body = [ 
	'<div>',
         '<ul class="list"...........
        ].join("");
   var Detail = {
    	title: '订单详情',
    	body : body,
        init : function($view,options){
        	this.render();
        	$view.addClass("detail").removeClass("hide");
        	$.hideLoading();
        },
        ....
   }
}

多模块管理

SPA预研

方案4:业务js,require对应业务html

<div class="container">
    <div id="index"></div>
    <!--表单[[-->
    <div class="main hide js-send"></div>
    <!--表单]]-->
    <div id="input-confirm"></div>
</div>
define(function(require,exports,module){
   var tpl =  require("text!/hybrid/mch/weixin/transfer_hk/mod/detail.shtml");
   var Detail = {
    	title: '订单详情',
    	body : tpl ,
        init : function($view,options){
        	this.render();
        	$view.addClass("detail").removeClass("hide");
        	$.hideLoading();
        },
        ....
   }
}

多模块管理

SPA预研

方案4:实现原理

 var load = function () {
  ......
  emit("resolve",emitData);
  emit("request",emitData);
 if (!emitData.requested && url) {//非模板文件
        _loadScript(url, function () {
// normal text
register({
  name: "text",

  ext: [".tpl", ".html",".shtml"],

  exec: function(uri, content) {
    globalEval('define("' + uri + '", [], "' + jsEscape(content) + '")')
  }
})


function xhr(url, callback) {
  var r = global.XMLHttpRequest ?
      new global.XMLHttpRequest() :
      new global.ActiveXObject("Microsoft.XMLHTTP")

  r.open("GET", url, true)

ajax请求,增加define逻辑

多模块管理

SPA预研

发布方案

编译时

交由工具js中注入html

多模块管理

SPA预研

模块配置文件

  var defaultUIOptions = {
    id: '',                               //路由名,注入点
    script:'',                            //模块名
    init: function() {},                  //初始化回调函数
    beforeinit: function() {},            //打开前回调
    afterinit: function() {},             //打开后回调
    beforeclose: function() {},           //关闭前回调
    afterclose: function() {}             //关闭后回调
  }
    $.fn.template = require("/res/scripts/mod/global/template.js");
    var tpl =  require("text!/hkwallet/zh_hk/balance/mod/detail.shtml");

    var Detail = {
    	title: '零錢详情',
    	body : tpl,
    	bodyClass:'rec-record-detail',
    	//更新body
    	beforeinit:function(options){//处理数据
    	    this.initModel(options);
    	    this.title =  $.Lang.get("detailTitle");
    		
    	},
        init : function($view,options,rr){
        	this.render(options);
        },

多模块管理

SPA预研

3、文件加载

2、页面结构

<body  class="rec-money">

<!--首页面]] -->
<div class="container" id="js-index">
   
</div>
<!--总结构-->
<div class="view-container" style="height: 100%;">

</div>

dust.use([uiModule['script']],function(module){
 var Router = {
        regRouter : function(){
        	//首页面
            $.SPA.r({
               path: 'js-index',//挂载点
               animate: '',  //入场动画效果
               bodyClass:"rec-money",
               type : 'index',
               script:'',
               beforeinit:function(){
               	    //國際化title
               	    this.title =  $.Lang.get("indexTitle");
               	    
               	    $("#balance").text(cur_type + $.Amount.fen2Yuan(balance||0));
               	    $("#go-record").unbind($.Env.CLICK_EVENT).bind($.Env.CLICK_EVENT,function(){
               	    	$.SPA.boot('record');
               	    });
               	    $(".pop-loading-txt").text($.Lang.get("loading"));
               	    //事件處理
               	    $.Env.goWalletIndex();
               	    $.Env.goDrawIndex();
               	    
               },
               afterinit:function(){
               	   $.hideLoading();
               }
            });
            //注册输入路由:
            $.SPA.r({
               path: 'detail',//挂载点
               animate: '',    //入场动画效果
               script:'/res/scripts/app/hkwallet/balance/detail.js'
            });
            //注册新的路由:
            $.SPA.r({
               path: 'record',//挂载点
               animate: '',                          //入场动画效果
               classname: '',                       //自定义样式名
               script:'/res/scripts/app/hkwallet/balance/recordmain.js'
            });
            
        },
        init : function(tmplate){
        	
            this.regRouter();
            $.SPA.startRun();
        }
    }

1、路由注册

多模块管理

SPA预研

6、数据传递

//value from session
 if(arg && arg.length == 0){
    			arg = SPA.Store.getItem(qs+"_"+uiModule['script'])
 }

module.init.call(module,$("#"+id),arg);

5、body更新

//默认在view-container上,统一在一个节点上,利于开发时,在首页加节点
var viewContainer = $("#"+id);
var view = viewContainer.length == 0 ? $(".view-container") : viewContainer;
//清事件
this.clearData(this.getAllNodes(view));
//注入
 view.html(html);

4、title更新

// hack在微信等webview中无法修改document.title的情况  
   var $iframe = $('<iframe style="display:none;" src="/favicon.ico"></iframe>').on('load', function() { 
                             setTimeout(function() {      
                                    $iframe.off('load').remove()      }, 0)  
                 }).appendTo($body);

多模块管理

SPA预研

1、资源加载

JS,html,css資源文件如何加載?

2、线上动态合并加载

1、全部打包一次性加载

性能优化

SPA预研

动态线上合并加载

动态合并 mgp_file_merge.cgi

/res/scripts/app/transfer_hk/send/sendmain.js<itemSplit>define(function(require,exports,module){
    require("/res/scripts/mod/global/spa.js");
    var hkwexin = require("/res/scripts/mod/global/hkweixin.js");
    var SendMain = {
        regRouter : function(){
        	//首页面
            $.SPA.r({
               id: 'js-guide',//挂载点
               animate: '',  //入场动画效果
               type : 'index',
               script:'',
               beforeinit:function(){
               	   $(".js-index").removeAttr("class").addClass("js-index hide-mod-pop-loading guide");
               	   
               	   $("#start_use").unbind($.Env.CLICK_EVENT).bind($.Env.CLICK_EVENT,function(){
               	   	   hkwexin.selectSingleContact({success:function(data){
                               var openid = data["info"]["openid"];
                               $.SPA.boot('input_page',{openid:openid});
                       }});
               	   	
               	   });
               },
               afterinit:function(){
               	   $.hideLoading();
               }
            });
            //注册输入路由:
            $.SPA.r({
            	beforeclose:function(){alert(3);},
               id: 'input_page',//挂载点
               animate: 'fadeIn',    //入场动画效果
               script:'/res/scripts/app/transfer_hk/send/inputpage.js'
            });
            //注册新的路由:
            $.SPA.r({
               id: 'ok_page',//挂载点
               animate: '',                          //入场动画效果
               classname: '',                        //自定义样式名
               script:'/res/scripts/app/transfer_hk/send/okpage.js'
            });
            
        },
        init : function(tmplate){
        	
        	this.initWX();
            this.regRouter();
            $.SPA.startRun();
        },
        initWX:function(){
        	
            hkwexin.initWX(para);
            
            hkwexin.hideShare({});
        }
    }

    return SendMain;

});<resSplit>/res/scripts/app/transfer_hk/send/inputpage.js<itemSplit>/**
 * 输入界面
 */
define(function(require,exports,module){
    var tpl =  require("text!/hybrid/mch/weixin/transfer_hk/mod/input_page.shtml");
    var InputExtend = require("/res/scripts/mod/global/inputextend.js");
    var datavalid = require("/res/scripts/mod/global/datavalid.js");
    $.Amount = require("/res/scripts/mod/global/amount.js");
    var PATH = $.Env.CGI_HOST+"cgi-bin/app/transfer/";
    var CGI = {//
        create_list : PATH + 'ia_transfers_create_list.cgi'//
    };
    var InputPage = {
        title: '轉賬',
        body : tpl,
        openid:"",
        //更新body
        beforeinit:function(options){//处理数据
        	options = options || [{}]
            $(".js-index").removeAttr("class").addClass("js-index hide-mod-pop-loading input");
            this.openid = options[0]["openid"];
        },
        init : function($view,options){
            this.render(options);
            $.hideLoading();
            this.bindEvent();
        },
        showTips: function(msg){
            $.Tips.showTips(msg, 2, 1, {top:"15px"});
        },
        render : function(options){
        	 $("#headImg").attr("src",HEAD_IMG_URL);
        	 $("#money").attr("placeholder","每筆最高限額為HK$"+$.Amount.fen2Yuan(PAY_MAX_AMOUNT));
        	 $("#receiver").val();
        	 new InputExtend('del',["money","receiver"]);
        	 
        	 new InputExtend('format',["money"]);
        	 
        },
        onValidFail:function(msg){
            InputPage.showTips(msg);
        },
        checkFormRules:function(){
            //配置
            return {
                "money":function(v){
                    if(!v){
                        return $.Lang.get("limitMoneyEmpty",'zh_cn');
                    }
                    return true;
                },
                "receiver":function(v){
                    if(!v){
                        return "姓名不能為空";
                    }
                    return true;
                }
            }
            
        },
        getNameRules:function(type){
            var data =  {
                "money":"transfer_amount",
                "receiver":"receiver_name"
               };
            if(type){
                data =  {
                 "transfer_amount":"money",
                "receiver_name":"receiver"
               };
            }
            return data;
        },
        validate:function(sucfn){
        	 datavalid.valid("form-translate",sucfn,this.onValidFail,this.checkFormRules(),null,this.getNameRules());
        },
        getParams:function(){
            
            var amount = $.trim($("#money").val());
            var name = $.trim($("#receiver").val());
            var params = {
               "curtype":'HKD',
               "transfer_amount":$.Amount.yuan2Fen(amount),
               "receiver_name":name
            };
            return params;
        },
        createListResult:function(data){
        	$.SPA.boot('ok_page',data);
        },
        bindEvent:function(){
        	$("#createlist").bind("tap",function(e){
                InputPage.validate(function(){
                     $.ajaxEx({
                        url : CGI["create_list"],
                        data : InputPage.getParams(),
                        onSuccess :InputPage.createListResult.bind(this)
                    });
                });
                
            });
        	
        }
    }
    return InputPage;
})

性能优化

SPA预研

//去掉缓存的事件以及上面缓存数据
    	clearData:function(elems){
    		//去除事件
            for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
            	$.event&&$.event.remove&&$.event.remove(elem,ZeptEvenNames);
            }
    	}

2、DOM事件 ?

性能优化

SPA预研

性能优化

3、DOM属性   ?

SPA预研

整体框架

SPA预研

开发流程

SPA预研

模块生命周期

SPA预研

案例-香港零錢包

SPA预研

案例-代码

define(function(require,exports,module){
    require("/res/scripts/mod/global/spa2.0.js");
    
    
    var Router = {
        regRouter : function(){
        	//首页面
            $.SPA.r({
               path: 'js-index',//挂载点
               animate: '',  //入场动画效果
               bodyClass:"rec-money",
               type : 'index',
               script:'',
               beforeinit:function(){
               	    //國際化title
               	    this.title =  $.Lang.get("indexTitle");
               	    
               	    $("#balance").text(cur_type + $.Amount.fen2Yuan(balance||0));
               	    $("#go-record").unbind($.Env.CLICK_EVENT).bind($.Env.CLICK_EVENT,function(){
               	    	$.SPA.boot('record');
               	    });
               	    $(".pop-loading-txt").text($.Lang.get("loading"));
               	    //事件處理
               	    $.Env.goWalletIndex();
               	    $.Env.goDrawIndex();
               	    
               },
               afterinit:function(){
               	   $.hideLoading();
               }
            });
            //注册输入路由:
            $.SPA.r({
               path: 'detail',//挂载点
               animate: '',    //入场动画效果
               script:'/res/scripts/app/hkwallet/balance/detail.js'
            });
            //注册新的路由:
            $.SPA.r({
               path: 'record',//挂载点
               animate: '',                          //入场动画效果
               classname: '',                       //自定义样式名
               script:'/res/scripts/app/hkwallet/balance/recordmain.js'
            });
            
        },
        init : function(tmplate){
        	
            this.regRouter();
            $.SPA.startRun();
        }
    }

    return Router;

});
/**
 *  列表页面
 */
define(function(require,exports,module){
    $.fn.template = require("/res/scripts/mod/global/template.js");
    var tpl =  require("text!/hkwallet/zh_hk/balance/mod/record.shtml");
    var Record = require("/res/scripts/app/hkwallet/balance/record.js");
    var RecordMain = {
        title: '零錢記錄',
        body : tpl,
        bodyClass:"rec-record",
        //更新body
        beforeinit:function(options){//处理数据
             this.title =  $.Lang.get("recordTitle");
        },
        getModel:function(options){
        },
        init : function($view,options,rr){
        	
        	$("#norecord").text($.Lang.get("norecord"));
        	$("#busy").text($.Lang.get("busy"));
            this.render(options);
        },
        render : function(options){
        	Record.init(function(){
        	   $.hideLoading();
        	});
        }
    }
    return RecordMain;
})

define(function(require, exports, module){
    require("/res/scripts/mod/global/iscroll-lite.js");
    $.Amount = require("/res/scripts/mod/global/amount.js");
    $.Date = require("/res/scripts/mod/global/date.js");
    var Flip = require("/res/scripts/mod/global/flipiscroll.js");
    $.request = require("/res/scripts/mod/hkwallet/balance/ajax.js");

	var _flip = null;
    var _iscrollObj = null;
    var Record = {
        pagesize : 9,   //一页数据多少
        offset : 0,     //查询偏移量
        totalNum : 0, //总记录数
        pageindex : 0, //第一页
        iScrollNode : $("#iScroll"),
        init : function(fn){
            //初始化下拉加载
            this.flipMoreRecord();
            this.getRecordList(fn);
            this.bindEvent();

            // 发送测速统计
            //$.SpeedLog.add();
            //$.SpeedLog.send(5, 9);

        },

        //获取记录
        getRecordList : function(fn){
            var url = $.Env.CGI_PRE + 'ewallet_querybalance_list.cgi';
            var data = {
                offset : Record.offset,
                limit : Record.pagesize //多查一条用于翻页
            }

            //取缴费记录成功处理
            var onSuc = function(data){
                var array = data.list || [];
                Record.totalNum = array.length;
                array = array.slice(0, Record.pagesize);

                if(Record.totalNum < 1){
                    $("#record .no-record").removeClass("hide");
                    Record.iScrollNode.addClass('hide');
                    return false;
                }

                Record.showRecordList(array);
            }
            var beforeSend = function(){
                // 上锁
                _flip.setLock(true);
            }
            var complete = function(data){
                _flip.setLock(false);
                fn&&fn();
            }
            
            var onFailure = function(data){
            	$("#record .busy").removeClass("hide");
            	return false;//不显示提示框
            }
            //请求配置信息
            var cfg = {
                url : url,
                data : data,
                onSuccess : onSuc,
                beforeSend : beforeSend,
                complete : complete,
                onFailure:onFailure
            }

            $.request.ajax(cfg);
        },

        //展示记录列表
        showRecordList : function(data){
            var dataArr = [];
            
            //更新數據
            $.each(data,function(k,v){
               
            	v.type_class = v.type == 1 ? "income":"";
                dataArr.push(v);
            })

            var tpl = $("#tpl_list").html();
            var html = $.format(tpl,dataArr,null,{
            	memo:function(value,key,index,recodes){
            		return  $.filterScript(value);
            	},
            	trade_time:function(value,key,index,recodes){
            		return value;
            	},
            	paynum:function(value,key,index,recodes){
            		return $.Amount.fen2Yuan(value||0);
            	},
            	cur_type:function(value,key,index,recodes){
                    return $.filterScript(cur_type);
                }
            	
            });
            $("#record-list").append(html);
            Record.offset += Record.pagesize;
            if (Record.onFlipCheck()) {
                _flip.showUpState();
            } else {
                _flip.setVisible();
            }
            _iscrollObj.refresh();
        },
        //绑定事件
        bindEvent : function(){
           
            $("#record-list").off("tap").on("tap","li",function(e){
                var target = $(e.currentTarget);
                $.SPA.boot('detail',{key:target.attr("key")});
            });
        },

        //滑动加载更多初始化
        flipMoreRecord : function(){
            _iscrollObj = $.browser.ie ? null :  new iScroll("iscroll");
            _flip = new Flip("iscroll", _iscrollObj, {
                "check":Record.onFlipCheck,
                "end": Record.onFlipEnd
            });
        },

        //滑动加载,判断是否还有记录可拉取
        onFlipCheck : function(){
            return Record.totalNum > Record.offset;
        },

        //滑动结束,加载数据
        onFlipEnd : function(){
            Record.getRecordList();
        }
    }

	
	
    return Record;
});
/**
 *  付款页面逻辑
 */
define(function(require,exports,module){
	$.fn.template = require("/res/scripts/mod/global/template.js");
    var tpl =  require("text!/hkwallet/zh_hk/balance/mod/detail.shtml");
    var CGI = {//
        query : $.Env.CGI_PRE + 'ewallet_querybalance_detail.cgi'//
    };
    
    var Detail = {
    	title: '零錢详情',
    	body : tpl,
    	bodyClass:'rec-record-detail',
    	//更新body
    	beforeinit:function(options){//处理数据
    	    this.initModel(options);
    	    this.title =  $.Lang.get("detailTitle");
    		
    	},
    	initModel:function(options){
    		this.model = options&&options[0];
    	},
        init : function($view,options,rr){
        	this.render(options);
        },
        render : function(options){
        	
        	this.queryDetail();
        	
        },
        queryDetail:function(){
        	
        	 var data = {
        	   bkid:this.model["key"]
        	 };
        	 $.ajaxEx({
                        url : CGI["query"],
                        data : data,
                        onSuccess :Detail.queryDetailResult.bind(this)
             });
        },
        //增加多语言配置
        fixData:function(data){
            var type      = $.Env.STATUS[data.type],
                sincoming = $.Lang.get(type);
        	data = $.extend(data,{
        		balance      : $.Amount.fen2Yuan(data.balance),
        		paynum       : $.Amount.fen2Yuan(data.paynum),
            	sincoming    : sincoming + $.Lang.get("money"),
            	stype        : $.Lang.get("type"),
            	type         : sincoming,
            	stime        : $.Lang.get("time"),
            	stransaction : $.Lang.get("transaction"),
            	snote        : $.Lang.get("note"),
            	paynumClass  :  data.type == 1 ? "income" : ""
        	})
        	
        	return data;
        },
        queryDetailResult:function(data){
        	var tmpl = $("#tmp-detail").template();
        	var html = tmpl(this.fixData(data));
        	$(".js-detail").html(html);
        	$.hideLoading();
        }
    }
    return Detail;
})

SPA预研

优缺点

优点:

5、功能配置化

2、模块级存储

1、体验流畅化

6、减少cgi模板化

4、维护轻量化

3、资源增量化

SPA预研

优缺点

缺点:

1、基于dust.js

2、无模块切换动画

3、无css片段化处理

4、基于配置化非规则化

5、CDN解决不了,依赖的依赖

SPA预研

规避问题

1、window上注册变量

2、基于seajs,保存在window中,每次须初始化变量

SPA预研

疑问解答

SPA预研

By lowinwu

SPA预研

spa单页面方案

  • 1,350