SPA
大纲
lowinwu|2015.11.25
1、使用意义
4、转账实践
3、问题&措施
2、业界方案
SPA
使用意义
切换速度
SPA
速度体现
1、页面间跳转,
2、页面回退,
资源重复下载、执行
资源重复下载,执行
SPA
业界方案1-pjax(ajax+pushstate)
http://userbag.co.uk/demo/pjax/
https://github.com/welefen/pjax
SPA

业界方案1-pjax(ajax+pushstate)
缺点
1、不支持刷新功能,需接合cgi
2、依赖jquery 3、不支持hash方式,兼容性差
SPA
业界方案2-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

缺点:1、压缩包78K
2、开发复杂
2、语法复杂
SPA
http://coenraets.org/blog/2013/06/building-modular-web-applications-with-backbone-js-and-requirejs-sample-app/
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;
}
});
});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();
}
});
});
}
});
});SPA
业界方案3

缺点: 1、MVC死板
2、开发流程复杂
SPA
面临问题
URL监听
代码隔离
穿透事件
首屏保障
缓存策略
文件合并
跨域方案
切屏方案
......
SPA
措 施
2、功能模块化加载
1、路由注册与监控
SPA
路由监控
1、注册路由
3、监控路由变化
2、ajax与tap/click事件
刷新&第三方跳转
onhashchange
重新包装&写hash
SPA
多模块加载
描述:复杂交互中,
?如何解决?
按需加载,代码隔离
SPA
多模块加载
方案1:html与js全注入首页
//注册路由
regRouters:function(){
$.SPA.regRouter("index",function(){ //回退首页以及进入首页处理
Send.showPage("index");
});
$.SPA.regRouter("input",function(){
Send.showPage("input");
});
$.SPA.regRouter("input-confirm",function(){
Send.showPage("input-confirm");
});
}<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>->消耗首屏&无效加载&js污染
SPA
多模块加载
方案2:动态加载js
regRouters:function(){//注册路由
$.SPA.r({
id: 'main_content',//挂载点
type:'index',//设置为首页
animate: '', //入场动画效果
script:'/res/scripts/app/transfer_hk/record.js'
});
},
init:fucntion(){
this.regRouter();//注册路由
$.SPA.startRun();//启动监听
}boot:function(id,options){
$.SPA.signLocaton({state:{path:id},func:function(){},type:true});
var uiModule = $.SPA.routers[id];
dust.use([uiModule['script']],function(module){
.......->消耗首屏时间&无效加载
SPA
多模块加载
方案3:动态加载html
define(function(require,exports,module){
$.PHtml.fetch("send",function(data){});
}<div class="container">
<div id="index"></div>
<!--表单[[-->
<div class="main hide js-send"></div>
<!--表单]]-->
<div id="input-confirm"></div>
</div>->代码维护成本高&偶合散乱
$.PHtml.r([
{
ver:'1.0',
url:"https://wsk.qq.com//hybrid/mch/weixin/transfer_hk/template/send.shtml",
id : "send"
}]);SPA
多模块加载
方案4:业务html嵌入业务js中
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();
},
....
}
}<div class="container">
<div id="index"></div>
<!--表单[[-->
<div class="main hide js-send"></div>
<!--表单]]-->
<div id="input-confirm"></div>
</div>->代码强偶合
SPA
多模块加载
方案5:业务js,require对应业务html
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();
},
....
}
}<div class="container">
<div id="index"></div>
<!--表单[[-->
<div class="main hide js-send"></div>
<!--表单]]-->
<div id="input-confirm"></div>
</div>SPA
多模块加载
方案5:实现原理?
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
多模块加载
方案5:架构位置

SPA
文件合并下载
方案1:
ajax动态合并下载
针对非js拦截修改
SPA
文件合并下载
方案1:JS,html合并

动态合并 mgp_file_merge.cgi
CGI难维护,需支持合并html,目前单独加载html
/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
文件合并(cdn)
方案2:JS,html合并
动态合并 https://mqq-imgcache.gtimg.cn/c/=
单独请求html,改造define实现存储
/**
* 椤甸潰鍥炶溅浜嬩欢鐨勮嚜鍔ㄧ洃鍚ā鍧�
* <p>
* 鐢变簬绉诲姩绔」鐩殑椤甸潰涓€鑸兘浼氬寘鍚玣orm鍏冪礌(鍦ㄦ媺璧烽敭鐩樻椂鍙互鍑虹幇纭)锛屾墍浠ュ湪鏂囨湰妗嗗唴鍥炶溅鐨勬椂鍊欒〃鍗曠粡甯歌嚜鍔ㄦ彁浜や粠鑰屽紩璧蜂竴浜涗笉蹇呰鐨勯棶棰橈紝
* 鍚屾椂涓轰簡鏀硅繘鐢ㄦ埛浣撻獙锛岀敱浜庨樆姝簡form琛ㄥ崟鐨勮嚜鍔ㄦ彁浜わ紝鎵€浠ュ湪鐢ㄦ埛杈撳叆瀹屾渶鍚庝竴涓〃鍗曢」鏃跺洖杞﹁Е鍙戣嚜鍔ㄦ彁浜�
* </p>
*
* <pre>
* var watch = require("../../../mod/global/watch");
*
* watch({
* "form" : "form[name='yourname']", //鍙己鐪� 榛樿鍙栨枃鏈妭鐐圭埗绾ф墍鍦ㄧ殑form鍏冪礌
* "target" : "鐩戝惉鐨刬nput妗嗙殑閫夋嫨鍣�",
* "button" : "琚姩鐩戝惉鐨勬寜閽簨浠剁殑鑺傜偣"
* })
* </pre>
*
* @class watch
* @module global
* @author chauvetxiao
*/
define("g/js/mod/global/watch-debug", [], function(require, exports, module) {
var param = {};
//鐢变簬缁戝畾浜嬩欢涓嶈兘浼犻€掑弬鏁� 鎵€浠ョ紦瀛橀厤缃璞�
var key = 0;
//璁℃暟鍣�
/**
* 瀵归〉闈笂鐨勮〃鍗曟彁浜や簨浠惰繘琛岀洃鍚�
*
* @method watch
* @param {Object} cfg 鐩戝惉鐨勫弬鏁伴厤缃」
*/
function watch(cfg) {
cfg = cfg || {};
var f = cfg.form ? $(cfg.form) : $(cfg.target).parents("form");
var target = $(cfg.target);
var button = $(cfg.button);
var pre_bind = $("input[data-bind-watch='1']");
key++;
pre_bind.off("keydown", onKeydownHandler);
//瑙g粦鏃ц妭鐐逛笂鍥炶溅浜嬩欢鐨勭粦瀹�
if (target) {
if (!target.data("bind-watch")) {
target.on("keydown", onKeydownHandler);
target.data("bind-watch", key);
param[key] = cfg;
}
}
if (!$(f).data("bind-watch")) {
$(f).on("submit", function(e) {
if (cfg.auto != true) {
e.preventDefault();
}
});
$(f).data("bind-watch", key);
}
}
/**
* 鎸夐敭寮硅捣鏃剁殑鐩戝惉浜嬩欢
* @method onKeydownHandler
* @private
* @param {Event} e 閿洏浜嬩欢
*/
function onKeydownHandler(e) {
if (e.keyCode == 13) {
e.preventDefault();
var cfg = param[$(e.target).data("bind-watch")] || {};
var f = cfg.form ? $(cfg.form) : $(cfg.target).parent("form");
var button = $(cfg.button);
if (cfg.auto == true) {
f && f.submit();
} else {
if (cfg.eventType) {
button.trigger(cfg.eventType);
} else {
button.trigger("tap");
button.trigger("click");
}
}
}
}
return watch;
});
.ico-icbc,.ico-cmb,.ico-ccb,.ico-abc,.ico-boc,.ico-cebb,.ico-ecitic,.ico-gdb,.ico-pingan,.ico-cmbc,.ico-cib,.ico-sdb,.ico-huarun,.ico-bosh,.ico-spdb,.ico-sdeb,.ico-nbcb,.ico-boco,.ico-bob,.ico-hkb,.ico-njcb,.ico-jsb,.ico-hzb,.ico-hxb,.ico-srcb,.ico-zjcb,.ico-post,.ico-psbc,.ico-cqcb,.ico-bsb,.ico-cbhb,.ico-nycbank,.ico-bocd,.ico-sznsh,.ico-hrbcb,.ico-jjccb,.ico-citic,.ico-ceb,.ico-pab,.ico-crb,.ico-comm,.ico-gzcb{position:relative;display:inline-block;vertical-align:middle;height:27px;line-height:27px;color:#333;font-size:1.2em;overflow:hidden;}.ico-icbc:before,.ico-cmb:before,.ico-ccb:before,.ico-abc:before,.ico-boc:before,.ico-cebb:before,.ico-ecitic:before,.ico-gdb:before,.ico-pingan:before,.ico-cmbc:before,.ico-cib:before,.ico-sdb:before,.ico-huarun:before,.ico-bosh:before,.ico-spdb:before,.ico-sdeb:before,.ico-nbcb:before,.ico-boco:before,.ico-bob:before,.ico-hkb:before,.ico-njcb:before,.ico-jsb:before,.ico-hzb:before,.ico-hxb:before,.ico-srcb:before,.ico-zjcb:before,.ico-post:before,.ico-psbc:before,.ico-cqcb:before,.ico-bsb:before,.ico-cbhb:before,.ico-nycbank:before,.ico-bocd:before,.ico-sznsh:before,.ico-hrbcb:before,.ico-jjccb:before,.ico-citic:before,.ico-ceb:before,.ico-pab:before,.ico-crb:before,.ico-comm:before,.ico-gzcb:before{content:" ";position:absolute;top:0;left:0;height:100%;width:100%;background:url("/res/weixin/creditcard/img/global/bank.png?v=20150923") no-repeat;-webkit-background-size:230px auto;background-size:230px auto;}@media only screen and(-webkit-min-device-pixel-ratio:1.5),only screen and(min-device-pixel-ratio:1.5){.ico-icbc:before,.ico-cmb:before,.ico-ccb:before,.ico-abc:before,.ico-boc:before,.ico-cebb:before,.ico-ecitic:before,.ico-gdb:before,.ico-pingan:before,.ico-cmbc:before,.ico-cib:before,.ico-sdb:before,.ico-huarun:before,.ico-bosh:before,.ico-spdb:before,.ico-sdeb:before,.ico-nbcb:before,.ico-boco:before,.ico-bob:before,.ico-hkb:before,.ico-njcb:before,.ico-jsb:before,.ico-hzb:before,.ico-hxb:before,.ico-srcb:before,.ico-zjcb:before,.ico-post:before,.ico-psbc:before,.ico-cqcb:before,.ico-bsb:before,.ico-cbhb:before,.ico-nycbank:before,.ico-bocd:before,.ico-sznsh:before,.ico-hrbcb:before,.ico-jjccb:before,.ico-citic:before,.ico-ceb:before,.ico-pab:before,.ico-crb:before,.ico-comm:before,.ico-gzcb:before{background-image:url("/res/weixin/creditcard/img/global/bank@2x.png?v=20150923");}}.ico-cmb{width:114px;}.ico-cmb:before{background-position:0 0;}.ico-boc{width:94px;}.ico-boc:before{background-position:0 -28px;}.ico-icbc{width:123px;}.ico-icbc:before{background-position:0 -56px;}.ico-ecitic,.ico-citic{width:112px;}.ico-ecitic:before,.ico-citic:before{background-position:0 -84px;}.ico-ccb{width:151px;}.ico-ccb:before{background-position:0 -112px;}.ico-abc{width:147px;}.ico-abc:before{background-position:0 -140px;}.ico-cmbc{width:184px;}.ico-cmbc:before{background-position:0 -168px;}.ico-gdb{width:115px;}.ico-gdb:before{background-position:0 -196px;}.ico-pingan,.ico-pab{width:140px;}.ico-pingan:before,.ico-pab:before{background-position:0 -224px;}.ico-cebb,.ico-ceb{width:158px;}.ico-cebb:before,.ico-ceb:before{background-position:0 -252px;}.ico-huarun,.ico-crb{width:99px;}.ico-huarun:before,.ico-crb:before{background-position:0 -280px;}.ico-spdb{width:96px;}.ico-spdb:before{background-position:0 -308px;}.ico-cib{width:144px;}.ico-cib:before{background-position:0 -336px;}.ico-sdb{width:169px;}.ico-sdb:before{background-position:0 -364px;}.ico-bosh{width:81px;}.ico-bosh:before{background-position:0 -392px;}.ico-sdeb{width:149px;}.ico-sdeb:before{background-position:0 -420px;}.ico-nbcb{width:94px;}.ico-nbcb:before{background-position:0 -448px;}.ico-boco,.ico-comm{width:122px;}.ico-boco:before,.ico-comm:before{background-position:0 -476px;}.ico-bob{width:125px;}.ico-bob:before{background-position:0 -504px;}.ico-hkb{width:189px;}.ico-hkb:before{background-position:0 -532px;}.ico-njcb{width:100px;}.ico-njcb:before{background-position:0 -560px;}.ico-jsb{width:116px;}.ico-jsb:before{background-position:0 -588px;}.ico-hzb{width:99px;}.ico-hzb:before{background-position:0 -616px;}.ico-hxb{width:120px;}.ico-hxb:before{background-position:0 -644px;}.ico-srcb{width:230px;}.ico-srcb:before{background-position:0 -672px;}.ico-zjcb{width:123px;}.ico-zjcb:before{background-position:0 -700px;}.ico-post{width:172px;}.ico-post:before{background-position:0 -728px;}.ico-psbc{width:172px;}.ico-psbc:before{background-position:0 -728px;}.ico-cqcb{width:151px;}.ico-cqcb:before{background-position:0 -756px;}.ico-bsb{width:139px;}.ico-bsb:before{background-position:0 -784px;}.ico-cbhb{width:157px;}.ico-cbhb:before{background-position:0 -812px;}.ico-nycbank{width:124px;}.ico-nycbank:before{background-position:0 -840px;}.ico-bocd{width:108px;}.ico-bocd:before{background-position:0 -868px;}.ico-sznsh{width:154px;}.ico-sznsh:before{background-position:0 -896px;}.ico-hrbcb{width:206px;}.ico-hrbcb:before{background-position:0 -924px;}.ico-jjccb{width:121px;}.ico-jjccb:before{background-position:0 -952px;}.ico-gzcb{width:106px;}.ico-gzcb:before{background-position:0 -980px;}.ico-icbc-s,.ico-cmb-s,.ico-ccb-s,.ico-abc-s,.ico-boc-s,.ico-cebb-s,.ico-ecitic-s,.ico-gdb-s,.ico-pingan-s,.ico-cmbc-s,.ico-cib-s,.ico-sdb-s,.ico-huarun-s,.ico-bosh-s,.ico-spdb-s,.ico-sdeb-s,.ico-nbcb-s,.ico-boco-s,.ico-bob-s,.ico-hkb-s,.ico-njcb-s,.ico-jsb-s,.ico-hzb-s,.ico-hxb-s,.ico-srcb-s,.ico-zjcb-s,.ico-post-s,.ico-psbc-s,.ico-cqcb-s,.ico-bsb-s,.ico-cbhbSPA
文件合并终极方案
编译时,

交由工具js中注入html
SPA
缓存处理

模块间传数据处理? sessionstoray
dust.cacheConfig(
{"/res/scripts/app/transfer_hk/app.js":"75D3429B50CAE23571EDEF4DCF35DFC9",
"/res/scripts/app/transfer_hk/detail.js":"7AF5377E24FFC9CFE519F3CCA3F68396",
"/res/scripts/app/transfer_hk/dust_config.js":"93584CD18610BA89C7444482F703BAB4",
"/res/scripts/app/transfer_hk/main.js":"A9BA65C9AF86592808E7B03C4F34C2DE",
"/res/scripts/app/transfer_hk/pay_result.js":"08CA5997EF09043357850E262F170BA4",
"/res/scripts/app/transfer_hk/receive.js":"DFA26B5A4B82C1DE2511DCA198958D71",
"/res/scripts/app/transfer_hk/record.js":"BD8843D4ACEDFCD72DD7A249B85B0537",
"/res/scripts/app/transfer_hk/send.js":"D3D6CEFCCFA3A803323A18DF61F9DC3D"
});SPA
内存处理
>jQuery Core 1.4.1 html()时支持去掉其节点中所有事件与缓存数据 http://code.jquery.com/jquery/
Text
SPA
整体架构图

SPA
开发流程

SPA
模块生命


SPA
转账项目-UI



SPA
转账项目-开发
<!-- 结构区域]] -->
<div class="container">
<!--引导頁[[-->
<div class="main js-guide hide" id="js-guide">
<div class="pic"><img width="262" src="/res/hybrid/img/mch/weixin/transfer_hk/guide_pic.png" alt="轉賬"></div>
<div class="btn-line">
<a class="btn-opt btn-green" style="/*position: relative;top: 200px;*/" href="#input_page" >立即使用</a>
</div>
</div>
<!--引导頁]]-->
<!--表单[[-->
<div class="main hide js-send" id="input_page"></div>
<!--表单]]-->
<!--表单[[-->
<div class="main hide js-input-confirm" id="ok_page"></div>
<!--表单]]-->
</div>
<?cs include:PARSE_PATH("/hybrid/mch/inc/js/js_wx_pay.html") ?>
<?cs include:PARSE_PATH("/hybrid/mch/inc/js/spa-dust.html") ?>
<?cs include:PARSE_PATH("/hybrid/mch/inc/js/transfer_hk/send.html") ?>
<script type="text/javascript">
var G_NOT_NEED_BASE = 1;
G_SPEED_TTL[1]=(new Date()).getTime();//dom初始化完成
dust.debug(true);
dust.use(["/res/scripts/app/transfer_hk/app.js","/res/scripts/app/transfer_hk/send/sendmain.js"],function(app,send){
app.init(function(){
send.init();
});
})
</script>define(function(require,exports,module){
require("/res/scripts/mod/global/spa.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");
$.hideLoading();
}
});
//输入界面
$.SPA.r({
id: 'input_page',//挂载点
animate: '', //入场动画效果
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.regRouter();
$.SPA.startRun();
}
}
return SendMain;
});/**
* 输入界面
*/
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,
//更新body
beforeinit:function(options){//处理数据
},
init : function($view,options,rr){
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));
$(".js-index").removeAttr("class").addClass("js-index hide-mod-pop-loading input");
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;
})/**
* 详情界面
*/
define(function(require,exports,module){
var tpl = require("text!/hybrid/mch/weixin/transfer_hk/mod/inputconfirm.shtml");
$.fn.template = require("/res/scripts/mod/global/template.js");
var InputPage = {
title: '轉賬',
body : tpl,
//更新body
beforeinit:function(options){//处理数据
var tpl = $(this.body).template();
this.body = tpl(this.getModel(options));
},
init : function($view,options){
this.render($view,options);
this.bindEvent();
$.hideLoading();
},
render : function($view,options){
$(".js-index").removeAttr("class").addClass("js-index hide-mod-pop-loading input-confirm");
},
getModel:function(options){
options = options||[];
var retObj = {},data = options[0];
if(data){
retObj = {
headImg:HEAD_IMG_URL,
transfer_amount : $.Amount.fen2Yuan(data.transfer_amount),
receiver_name : data.receiver_name,
transfer_fee : data.transfer_fee,
transfer_sum : $.Amount.fen2Yuan(data.transfer_sum)
}
}
return retObj;
},
bindEvent:function(){
}
}
return InputPage;
})SPA
遗留问题
模块间切换效果(完善中)
性能(内存)监控
工具建设,html注入
css按需加载
......
SPA
Thanks

spa
By lowinwu
spa
spa单页面方案
- 1,380