jquery mobile的mvc实践并总结

貌似jquery.mobile和backbones的一些实践网上有很多了,我就分享下最近做的jquery.mobile的应用,中间mvc和数据、逻辑隔离部分的设计和代码。

 

首先就是“单入口模式”——这种设计无处不在啊。

 

在jquery.mobile的设计里,有很多page切换的钩子方法,具体可以参考官方文档demos/docs/api/events.html里的列表。

 

因为我做的应用大多是和和传统的request那种模式差不多的,就是在page渲染之前,先对page的dom做一次数据组装,所以用到较多的是pagebeforecreate这个方法,上文说的“单入口”就是这个方法做入口,然后派发,比作DispatchController。

 

 

贴下代码:

 

// mobile page 工具类,获取dom元素的值,跳转事件的过滤等
// need pageData对象,本类的实例对象
// x.js page.data.js
var PageUtils = {
	initBindLl: ['pagebeforechange', 'pagebeforecreate', 'db'], 

	initApp: function(){
		var _pageBase = $("div[data-role='page'],div[data-role='dialog']");
		if(PageUtils.initBindLl.contains('pagebeforechange')){
			_pageBase.live("pagebeforechange", function(e, data){
				// while loading a page by URL
				if(typeof data.toPage === "string"){
					var currentPage = IPage.parsePage(document.location.href);
					var toPage = IPage.parsePage(data.toPage);

					var pageName = IPage.parsePageName(data.toPage);
					var pageObj = PageUtils.pages[pageName];
					if(pageObj){
						pageObj.setPageInfo(toPage, currentPage);
						var flag = pageObj.canAccess();
						if(flag === false){
							e.preventDefault();
						}
					}
				}else if(typeof data.toPage === "object"){
					// load page dom
				}
			});
		}

		if(PageUtils.initBindLl.contains('pagebeforecreate')){
			_pageBase.live('pagebeforecreate', function(e){
				var currentPage = IPage.parsePage(document.location.href);
				var toPage = IPage.parsePage(this.baseURI);

				var pageName = IPage.parsePageName(this.baseURI);
				var pageObj = PageUtils.pages[pageName];
				if(pageObj){
					pageObj.setPageInfo(toPage, currentPage, this);
					pageObj.initDomEntry();
				}
			});
		}

		if(PageUtils.initBindLl.contains('db')){
			// page db initialize
			PageDb.initTables();
		}
	}, 

	// application pages
	pages: {
		pageTaskLl: new PageTaskLl(), 

		pageOne: new PageOne,
                // add your pages here

		
		dump: ''
	}, 

	dump: ''
};

 

 

其中抽象了一组application pages,具体实现如下,先定义个接口

 

/**
* Begin class defination Ipage : mobile page 抽象类,一个页面的接口方法
*/
var IPage = Base.extend({
	// mobile.path.parseUrl : page info
	info: null, 
	from: null, 

	// 对dom page的引用
	_page: null, 

	constructor: function(){},

	setPageInfo: function(i, f, pageDom){
		this.info = i;
		this.from = f;
		if(pageDom)
			this._page = $(pageDom);
	}, 

	// 页面dom初始化
	initDomEntry: function(){
		this.initDomBefore();
		this.initDom();
	}, 
	initDomBefore: function(){
		// append parameter
		var search = this.info.search;
		this.dom('#surveyNav a, a.urlPend').each(function(){
			var srcUrl = $(this).attr('href');
			$(this).attr('href', srcUrl + search);
		});
	}, 
	// need to overwrite 模板方法
	initDom: function(){}, 

	params: function(){
		return IPage.parseSearch(this.info.search);
	}, 

	canAccess: function(){return true;}, 

	dom: function(selecter){
		return this._page.find(selecter);
	}, 

	dump : '' 
	},{

	// 辅助方法
	// 获取url参数键值对,不包含'?'
	parseSearch: function(query){
		var data = {};
		if(query){
			_.each(query.substring(1).split('&'), function(one){
				var arr = one.split('=');
				if(arr.length == 2)
					data[arr[0]] = arr[1];
			});
		}
		return data;
	}, 

	// 获取url参数键值对,包含'?'
	parseSearchByUrl: function(url){
		return this.parseSearch(url.substring(url.indexOf('?')));
	}, 

	parsePageName: function(url){
		var filename = IPage.parsePage(url).filename;
		return filename.substring(0, filename.lastIndexOf('.'));
	}, 

	parsePage: function(url){
		return $.mobile.path.parseUrl(url);
	}, 

	// 一些通用的业务逻辑相关的方法
	commonFn: {
	}, 

	// 一些通用的dom生成的方法
	commonDomFn: {
	}, 

	dump : '' 
});

 

这样,一个mobile页面就对应一个IPage子类的实例对象,举例:

 

/**
* Begin class defination PageTaskLl 
* 任务列表
*/
var PageTaskLl = IPage.extend({
	// 页面dom初始化
	initDom: function(){
		var _this = this;
		var _navLl = _this.dom('#navSub button');
		_navLl.click(function(e){
			// 分页显示,默认显示第一页,一页10条记录
			_this.taskLlRefresh($(this).attr('val'), 1, 10);

			PageTheme.toggleBtnClass($(this), 'c', 'b');
			PageTheme.toggleBtnClass(_navLl.not(this), 'b', 'c');
		});

		// 根据参数显示已完成还是未完成,默认是所有
		var params = this.params();
		var type = params.type || 'all';
		_navLl.filter('[val={0}]'.format(type)).trigger('click');
	}, 

	taskLlRefresh: function(type, cp, npp){
		var _ul = this.dom('ul[data-role="listview"]');
		_ul.empty();

		var _this = this;
		// 异步的
		this.getCaseLl(type, cp, npp, function(item){
			_ul.append(_this.domFn.getTaskLi(item));
		}, function(pager){
			_ul.listview('refresh');

			// 分页导航
			var _piDiv = _this.dom("#taskLl");
			_piDiv.html(pager.getHtml2());
			_piDiv.find("a.piLink").click(function(){
				var cpTarget = parseInt($(this).text());
				_this.taskLlRefresh(type, cpTarget, npp);
			});
		});
	}, 

	// **** **** **** **** **** **** **** ****
	// **** **** **** **** **** **** **** ****
	// 数据库相关操作
	// 获取案件列表
	getCaseLl: function(type, cp, npp, fn, callback){
		var sql = 'select * from t_claim_case where 1 = 1';
		var args = [];
		if(type && 'all' != type){
			sql += ' and type = ?';
			args.push(type);
		}
		XDB.piAndMap(sql, args, cp, npp, fn, callback);
	}, 

	// **** **** **** **** **** **** **** ****
	// **** **** **** **** **** **** **** ****
	// dom相关操作
	domFn: {
		// 任务列表
		// 建议使用easyTemplate做html代码生成,比较简洁明了
		getTaskLi: function(item){
			var fnDd = XHtml.createFn('dd');
			var tpl2 = fnDd(
					XHtml.tag('报案号:' + item.caseNo + '(' + item.type + ')', 'h3') 
					+ '<br />'
					+ XHtml.tag('车牌号:' + 
						item.vehicleNo + 
						'&nbsp;&nbsp;' + '联系人:' + 
						item.concatName, 'p')) + 
				fnDd('联系人手机:' + item.concatPhone) + 
				fnDd('报案时间:' + item.claimDate.format());
			var tpl = XHtml.alink(tpl2, 'pageCaseBase.gy?caseNo={0}'.format(item.caseNo));

			var imgInner = '<img src="{0}mb/claim/img/case.png" />'.format(X.appPath);
			return XHtml.tag(imgInner + tpl, 'li');
		}
	}, 


	dump : '' 
	},{
	dump : '' 
});

 

页面效果截图如下:

 

jquery mobile的mvc实践并总结_第1张图片

 

 

 

 

PS,通过这个设计(一个页面对应一个js文件),如果js的oo方面设计合理些,业务逻辑不太复杂的话,可以做出来比较复杂的页面(大量的对话框,关联菜单,过滤表格,事件处理等)。

 

 

希望这些实践能为感兴趣的筒子们有所帮助。

你可能感兴趣的:(jquery,mobile)