extjs4 省市区选择器

    前期时间,需求说后台管理系统(前端用extjs开发)的省市区三级联动选择太麻烦,能不能做成类似于日期选择控件,直接给用户去选择。当时比较忙,说先凑合着用,最近稍微闲一下,就研究了一下。

    对extjs不是很熟,在网上看到了一篇文章,写得不错,http://skirtlesden.com/articles/html-and-extjs-components

结合Extjs自带的DatePicker源代码,写了一个ProvinceCityAreaPicker,

/**
 * 
 */
Ext.define('Ext.ux.ProvinceCityAreaPicker', {
	extend : 'Ext.panel.Panel',
	requires : [ 'Ext.XTemplate', , 'Ext.EventObject', 'Ext.fx.Manager' ],
	alias : 'widget.provincecityareapicker',

	tpl : [ '<div id="_provincecityareapicker-province", role="presentation" {provinceHide:this.hidePCA}>',// province
	// div
	'<table class="x-datepicker-inner" cellspacing="0" role="presentation">',// table
	'<tbody role="presentation">', // tbody
	'<tr role="row">',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'</tr>', '<tr role="row">',//
	'<tpl for="provinceList">',//
	'{#:this.isRowEnd}',//
	'<td role="gridcell" title="{provinceName}-{provinceCode}" data-code="{provinceCode}" class="x-datepicker-active x-datepicker-cell">',//
	'<a role="presentation" hidefocus="on" class="x-datepicker-date" href="#">{provinceName:this.ellipseText}',//
	'</td>',//
	'</tpl>',//
	'</tr>',//
	'</tbody>',// tbody
	'</table>',// table
	'</div>', '<div id="_provincecityareapicker-city", role="presentation" {cityHide:this.hidePCA}>',// city
	'<table class="x-datepicker-inner" cellspacing="0" role="presentation">',// table
	'<tbody role="presentation">', // tbody
	'<tr role="row">',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'</tr>', '<tr role="row">',//
	'<tpl for="cityList">',//
	'{#:this.isRowEnd}',//
	'<td role="gridcell" title="{cityName}-{cityCode}" data-code="{cityCode}" class="x-datepicker-active x-datepicker-cell">',//
	'<a role="presentation" hidefocus="on" class="x-datepicker-date" href="#">{cityName:this.ellipseText}',//
	'</td>',//
	'</tpl>',//
	'</tr>',//
	'</tbody>',// tbody
	'</table>',// table
	'</div>', '<div id="_provincecityareapicker-area", role="presentation" {areaHide:this.hidePCA}>',// areas
	'<table class="x-datepicker-inner" cellspacing="0" role="presentation">',// table
	'<tbody role="presentation">', // tbody
	'<tr role="row">',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'<td role="gridcell" title="" class="x-datepicker-active x-datepicker-cell"></td>',//
	'</tr>', '<tr role="row">',//
	'<tpl for="areaList">',//
	'{#:this.isRowEnd}',//
	'<td role="gridcell" title="{areaName}-{areaCode}" data-code="{areaCode}" class="x-datepicker-active x-datepicker-cell">',//
	'<a role="presentation" hidefocus="on" class="x-datepicker-date" href="#">{areaName:this.ellipseText}',//
	'</td>',//
	'</tpl>',//
	'</tr>',//
	'</tbody>',// tbody
	'</table>',// table
	'</div>', {
		isRowEnd : function(index) {
			index--;
			var end = index !== 0 && index % 4 === 0;
			return end ? '</tr><tr role="row">' : '';
		},
		ellipseText : function(text) {
			// out.push(values);
			return Ext.String.ellipsis(text, 6, true);
		},
		hidePCA : function(hide) {
			return hide ? 'class="x-hidden"' : '';
		}
	} ],

	titleAlign : 'center',
	frame : false,
	border : true,
	bodyStyle : {
		padding : '10px'
	},
	width : 400,

	initComponent : function() {
		var me = this;

		me.callParent();

		me.selectedCls = 'x-datepicker-selected';

		me.addEvents('select');
	},

	beforeRender : function() {
		var me = this;

		me.callParent();

		me.sendProvinceData();

		Ext.applyIf(me, {
			data : {}
		});

		me.current = {
			provinceList : me.provinceList,
			cityList : me.cityList,
			areaList : me.areaList,
			provinceHide : false,
			cityHide : true,
			areaHide : true
		}

		Ext.apply(me.data, me.current);

		me.protoEl.unselectable();
	},

	onRender : function(container, position) {
		var me = this;
		console.log(me.header);
		me.callParent(arguments);

		me.initProvinceCellEl();
	},

	initProvinceCellEl : function() {
		var me = this;
		me.provCt = me.el.select('#_provincecityareapicker-province');
		me.provTdCells = me.provCt.select('table tbody tr:visible(true) td');
		me.provCells = me.provTdCells.select('a');
	},

	initCityCellEl : function() {
		var me = this;
		me.cityCt = me.el.select('#_provincecityareapicker-city');
		me.cityTdCells = me.cityCt.select('table tbody tr:visible(true) td');
		me.cityCells = me.cityTdCells.select('a');
	},

	initAreaCellEl : function() {
		var me = this;
		me.areaCt = me.el.select('#_provincecityareapicker-area');
		me.areaTdCells = me.areaCt.select('table tbody tr:visible(true) td');
		me.areaCells = me.areaTdCells.select('a');
	},

	initEvents : function() {
		var me = this;
		me.callParent();
		me.provCells.on('click', me.provClickHandler, me);
	},

	sendProvinceData : function() {
		var me = this;
		if (Ext.isEmpty(me.provinceList)) {
			Ext.Ajax.request({
				method : 'POST',
				url : me.contextPath + '/main/findProvince.action',
				async : false,
				success : function(response, eOpts) {
					var data = Ext.decode(response.responseText);
					if (data && data.queryList) {
						me.provinceList = data.queryList;
					}
				},
				failure : function(response, eOpts) {
					me.provinceList = null;
				}
			});
		}
	},

	sendCityData : function(provinceCode, cache) {
		var me = this;

		var mustRequest = true;
		if (cache && Ext.isEmpty(me.cityList)) {
			mustRequest = false;
		}

		if (mustRequest) {
			Ext.Ajax.request({
				method : 'POST',
				url : me.contextPath + '/main/findCity.action',
				async : false,
				params : {
					code : provinceCode
				},
				success : function(response, eOpts) {
					var data = Ext.decode(response.responseText);
					if (data && data.queryList) {
						me.cityList = data.queryList
					}
				},
				failure : function(response, eOpts) {
					me.cityList = null;
				}
			});
		}
	},

	sendAreaData : function(cityCode, cache) {
		var me = this;

		var mustRequest = true;
		if (cache && Ext.isEmpty(me.areaList)) {
			mustRequest = false;
		}

		if (mustRequest) {
			Ext.Ajax.request({
				method : 'POST',
				url : me.contextPath + '/main/findArea.action',
				async : false,
				params : {
					code : cityCode
				},
				success : function(response, eOpts) {
					var data = Ext.decode(response.responseText);
					if (data && data.queryList) {
						me.areaList = data.queryList
					}
				},
				failure : function(response, eOpts) {
					me.areaList = null;
				}
			});
		}
	},

	updateProvince : function() {
		var me = this;
		Ext.apply(me.current, {
			provinceHide : false,
			cityHide : true,
			areaHide : true
		});
		me.update(me.current);
		me.setTitle('省份选择');
		me.initProvinceCellEl();
		me.provCells.on('click', me.provClickHandler, me);
	},

	updateCity : function() {
		var me = this;
		Ext.apply(me.current, {
			provinceHide : true,
			cityHide : false,
			areaHide : true,
			cityList : me.cityList
		});
		me.update(me.current);
		me.setTitle('城市选择');
		me.initCityCellEl();
		me.cityCells.on('click', me.cityClickHandler, me);
	},

	updateArea : function() {
		var me = this;
		Ext.apply(me.current, {
			provinceHide : true,
			cityHide : true,
			areaHide : false,
			areaList : me.areaList
		});
		me.update(me.current);
		me.setTitle('区域选择');
		me.initAreaCellEl();
		me.areaCells.on('click', me.areaClickHandler, me);
	},

	provClickHandler : function(evt, prov, opts) {
		evt.stopEvent();
		evt.stopPropagation();
		var me = this;
		var href = Ext.fly(prov);
		if (href && href.getAttribute('href')) {
			me.el.select('#_provincecityareapicker-province table tbody tr:visible(true) td').removeCls(me.selectedCls);
			var tdEle = href.parent();
			var provinceCode = tdEle.getAttribute('data-code');
			me.updateCurrentProvince(provinceCode);
			tdEle.addCls(me.selectedCls);
			me.mask();
			me.sendCityData(provinceCode, false);
			me.updateCity();
			me.unmask();
		}
	},

	updateCurrentProvince : function(provinceCode) {
		var me = this;
		if (me.current && me.current.provinceList && provinceCode) {
			Ext.each(me.provinceList, function(prov, index) {
				if (prov && prov.provinceCode == provinceCode) {
					Ext.apply(me.current, {
						province : prov
					});
					return;
				}
			});
		}
	},

	cityClickHandler : function(evt, city, opts) {
		evt.stopEvent();
		evt.stopPropagation();
		var me = this;
		var href = Ext.fly(city);
		if (href && href.getAttribute('href')) {
			me.el.select('#_provincecityareapicker-city table tbody tr:visible(true) td').removeCls(me.selectedCls);
			var tdEle = href.parent();
			var cityCode = tdEle.getAttribute('data-code');
			me.updateCurrentCity(cityCode);
			tdEle.addCls(me.selectedCls);
			me.mask();
			me.sendAreaData(cityCode, false);
			me.updateArea();
			me.unmask();
		}
	},

	updateCurrentCity : function(cityCode) {
		var me = this;
		if (me.current && me.current.cityList && cityCode) {
			Ext.each(me.cityList, function(city, index) {
				if (city && city.cityCode == cityCode) {
					Ext.apply(me.current, {
						city : city
					});
					return;
				}
			});
		}
	},

	areaClickHandler : function(evt, area, opts) {
		evt.stopEvent();
		evt.stopPropagation();
		var me = this, handler = me.handler;
		var href = Ext.fly(area);
		if (href && href.getAttribute('href')) {
			me.el.select('#_provincecityareapicker-area table tbody tr:visible(true) td').removeCls(me.selectedCls);
			var tdEle = href.parent();
			var areaCode = tdEle.getAttribute('data-code');
			me.updateCurrentArea(areaCode);
			tdEle.addCls(me.selectedCls);
			var c = me.current;
			me.setValue({
				province : c.province,
				city : c.city,
				area : c.area
			});
			me.fireEvent('select', me, me.value);
			if (handler) {
				handler.call(me.scope || me, me.value);
			}
			me.onSelect();
		}
	},

	updateCurrentArea : function(areaCode) {
		var me = this;
		if (me.current && me.current.areaList && areaCode) {
			Ext.each(me.areaList, function(area, index) {
				if (area && area.areaCode == areaCode) {
					Ext.apply(me.current, {
						area : area
					});
					return;
				}
			});
		}
	},

	onSelect : function() {
		if (this.hideOnSelect) {
			this.hide();
		}
	},

	setValue : function(value) {
		this.value = value;
		return this;
	},

	getValue : function() {
		return this.value;
	},

	prevHandler : function() {
		var me = this;
		if (!me.current.cityHide && !Ext.isEmpty(me.current.provinceList)) {
			me.updateProvince();
		} else if (!me.current.areaHide && !Ext.isEmpty(me.current.cityList)) {
			me.updateCity();
		} else {
			return;
		}
	},

	nextHandler : function() {
		var me = this;
		if (!me.current.provinceHide && !Ext.isEmpty(me.current.cityList)) {
			me.updateCity();
		} else if (!me.current.cityHide && !Ext.isEmpty(me.current.areaList)) {
			me.updateArea();
		} else {
			return;
		}
	}
});

代码写的比较粗糙,不过对于后台管理系统来说已经够用了。

最后上几张图:

174530_id2I_183476.png

174530_3MOy_183476.png

174530_u5u1_183476.png


转载于:https://my.oschina.net/u/183476/blog/306883

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值