手工打造Extjs

在没接触Ext时都不知道javascript是一门可以面向对象的语言,接触之后喜欢上了javascript这门语言,看了一些js相关书籍,想起之前项目经理说过的一句话,只有站在创造者的角度去想问题,才能以最好的方法解决问题。如果我以Ext创造者的角度去考虑问题,那么我的技术可以更上一层楼吧!

因为没有用Ext做过真正项目,只是看了官方的例子和api文档,看了一些源码,以自己的理解山寨了一下,命名为Design。之前看了< javascript设计模式>,思路大部分都来源于这本书,做这个只是兴趣爱好,功能上有很多细节没有实现(工作量较大),项目中用到什么功能就去完善那个功能。之前失败五次都因设计上不合理不得不重新做,而这回感觉还不错所以就拿出来给客位看官瞧瞧,如有建议还请多多指教。




使用的类库:

    jquery   // 因为jquery的插件比较丰富所以放弃使用Ext Core而选择jquery

    jquery 树插件 zTree

   jscal2 日期控件 

   TrimPath javascript模板引擎

   highcharts javascript 图表插件


下面先介绍主要的功能,下面列出的是项目中主要实现的功能。


1、类体系

Extjs中得类体系非常出色,这里我模仿了Extjs类体系中主要的功能,主要有 define(定义类)、create(创建对象)、widget(使用别名创建对象)。

define函数主要有2个参数,参数1是类名也是js文件的路径,参数2是配置参数。

Design.define(“Design.panel.Panel”, {      
    extend: ‘Design. Compoment,             // 继承某个类
    requires: [‘Design. toolbar.Toolbar’], // 这个类需要关联其它的类
    alias: 'widget.panel’,                  // 这个类的别名
    mixins: ['Design.util.Observable']       // 混入某个类
    constructure:function(){},               // 构造函数
});


在上面我们定义了一个类,就可以使用create函数来创建它。第一个参数是名称,第二个参数是参数,参数会被传送到上面的构造函数中。

var panel = Design.create("Design.panel.Panel",{
        id: 'panel',
	name: '面板'
});

widget与create几乎是一样的,唯一不同就是可以用别名来创建它,上面将Design.panel.Panel 别名定义成 panel。

var panel = Design.widget("panel",{
        id: 'panel',
	name: '面板'
});


2、Require按需加载JS文件,Extjs4中加入的功能,为了减少页面的压力,只加载需要的文件。

Design.setPath(“app”);   //配置路径。
Design.require(“Design.panel.Panel”);  //加载这个类,会加载 app/panel/Panel.js 这个文件。


上面两行代码是要去找 app/panel/Panel.js 并加载,在执行这个文件时 Design.define方法会检索extend、requires、mixins 属性会发现有关联类Design.Compoment、Design.toolbar.Toolbar’、 Design.util.Observable,所以会先加载这三个文件,完成后继续执行继承和混入。在Design.require方法执行完后会寻找页面中的Design.onRady方法并调用,在页面加载完成并且需要的文件加载完后执行,与jquery.ready类似。


 3、Design.util.Observable 监听者类

 继承或混入监听者对象可以使类可以被监听事件。


4、数据层

Design.data.Model 模型

Design.data.Store  数据源 

Model可以定义字段,而Store可以看成是模型的集合,主要用于控件装载模型作为显示内容,与监听数据的变化以及时更新控件。


5、Design. Compoment 基础组件类

这个基础组件类实现了对象与对象之间相组合的规则(组合模式)。

以表格为例它就组合了很多个对象 row(行)、cell(列)、table(表格)、header(标题栏)以及panel(面板),每一个组件对象中都会有一个HTMLElement对象,组合后将会生成下面的html片段。

<div id="panel-1">
	<div id = "header-1">
		标题
	</div>
	<table id = "table-1">
		<tr id = "row-1">
			<td id = "cell-1"></td>
		</tr>
	</table>
</div>
其中id可以使用var panel = Design.getCmp('panel-1')来获取这个控件对象,panel. destroy ()来销毁这个控件。

还实现一些基础功能:显示、销毁、大小改变、初始化Element、初始化子项、回调函数 ….等功能,几乎所有组件都继承自Compoment类。


下面说说缺点,缺点是没能实现Extjs中得layout布局功能(没有思路)导致组件之间无法灵活的布局(但可以设置Style的float属性来布局)、浏览器兼容有时需要配置style属性自己来写兼容样式(也可以说灵活吧!),以及性能上有些不理想。先介绍到这里,下面是一些截图 与Extjs相比较,第一张图是 Extjs官方例子group-header-grid 第二张是Design做出的效果,也可以比较下Extjs与Design的代码。


Code:

Ext.require([
    'Ext.grid.*',
    'Ext.data.*',
    'Ext.util.*',
    'Ext.state.*'
]);

Ext.onReady(function() {
    Ext.QuickTips.init();

    // sample static data for the store
    var myData = [] // 省略;

    /**
     * Custom function used for column renderer
     * @param {Object} val
     */
    function change(val) {
        if (val > 0) {
            return '<span style="color:green;">' + val + '</span>';
        } else if (val < 0) {
            return '<span style="color:red;">' + val + '</span>';
        }
        return val;
    }

    /**
     * Custom function used for column renderer
     * @param {Object} val
     */
    function pctChange(val) {
        if (val > 0) {
            return '<span style="color:green;">' + val + '%</span>';
        } else if (val < 0) {
            return '<span style="color:red;">' + val + '%</span>';
        }
        return val;
    }

    // create the data store
    var store = Ext.create('Ext.data.ArrayStore', {
        fields: [
           {name: 'company'},
           {name: 'price',      type: 'float'},
           {name: 'change',     type: 'float'},
           {name: 'pctChange',  type: 'float'},
           {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
        ],
        data: myData
    });

    // create the Grid
    var grid = Ext.create('Ext.grid.Panel', {
        store: store,
        columnLines: true,
        columns: [{
            text     : 'Company',
            flex     : 1,
            sortable : false,
            dataIndex: 'company'
        }, {
            text: 'Stock Price',
            columns: [{
                text     : 'Price',
                width    : 75,
                sortable : true,
                renderer : 'usMoney',
                dataIndex: 'price'
            }, {
                text     : 'Change',
                width    : 75,
                sortable : true,
                renderer : change,
                dataIndex: 'change'
            }, {
                text     : '% Change',
                width    : 75,
                sortable : true,
                renderer : pctChange,
                dataIndex: 'pctChange'
            }]
        }, {
            text     : 'Last Updated',
            width    : 85,
            sortable : true,
            renderer : Ext.util.Format.dateRenderer('m/d/Y'),
            dataIndex: 'lastChange'
        }],
        height: 350,
        width: 600,
        title: 'Grouped Header Grid',
        renderTo: 'grid-example',
        viewConfig: {
            stripeRows: true
        }
    });
});



Code

Design.Loader.setPath('Design', '../../src');
Design.require(['Design.grid.Panel', 'Design.data.Model','Design.data.Store']);  // 本例中需要用到这三个类


var myData = [] // 数据较大省略

Design.onReady(function(){
	
	Design.define('GridModel', {    // 声明模型
		extend: 'Design.data.Model',
		fields: [{
			name: 'company',
			type: 'string'
		},{
			name: 'price',
			type: 'string'
		},{
			name: 'change',
			type: 'string'
		},{
			name: 'pctChange',
			type: 'string'
		},{
			name: 'lastChange',
			type: 'string'
		}]
	});
	
	var store = Design.create('Design.data.Store', {  // 创建模型集合
		model: 'GridModel',
		data: myData
	});
	
	function change(m,val) {   
		if (val > 0) {
			return '<span style="color:green;">' + val + '</span>';
		} else if (val < 0) {
			return '<span style="color:red;">' + val + '</span>';
		}
		return val;
	}
	
	function pctChange(m,val) {
		if (val > 0) {
			return '<span style="color:green;">' + val + '%</span>';
		} else if (val < 0) {
			return '<span style="color:red;">' + val + '%</span>';
		}
		return val;
	}
	
	function lastChange(m,val) {
		return Design.dateFormat(new Date(val),"yyyy年MM月dd日");
	}
	
	function price(m,val) {
		if (!val) {
			return val
		}
		return "$ " + val;
	}
	
	var grid = Design.widget('grid', {    // 创建一个表格
		title: {
			text: 'Grouped Header Grid'  // 标题
		},
		style: {						// 表格的样式
			height: 350,  				// 表格高度
			width: 600					// 表格宽度
		},
		columns: [{						// 列的配置与Extjs非常相似		
			text: 'company', 
			width: 200, 
			dataIndex: 'company', 		
			locked: true				
		}, {
			text: 'Stock Price', 
			columns: [					
				{text: 'price', width: 125, dataIndex: 'price', renderer: price},
				{text: 'change', width: 125, dataIndex: 'change', renderer: change},
				{text: 'pctChange', width: 125, dataIndex: 'pctChange', renderer: pctChange}
			]
		}, {
			text: 'lastChange', 
			width: 135, 
			dataIndex: 'lastChange', 
			renderer: lastChange
		}],
		drag: true,						// 使表格变为可拖动相当定义成了Ext.window.Window
		store:store						
	});
	
	grid.show();						// 显示到页面
	
	
});	

接下来发一些演示截图与代码,大部分都是模仿Extjs例子做的,感兴趣的话可以下载源码。


表格工具栏演示。

var grid = Design.widget('grid', {
	title: {
		text: 'toolbar'
	},
	toolbar: [{
		dock: 'top',
		items: [{
			xtype: 'textfield',
			style: {
				'float': 'left'
			},
			labelWidth: 40,
			label: 'text',
			fieldStyle: {
				width: 100
			},
			handler: function() {
				
			}
		},{
			xtype: 'radiogroup',
			style: {
				float: 'left'
			},
			items: [
				{boxLabel: 'radio1', value:'1', name: 'chartType', checked: true},
				{boxLabel: 'radio2', name: 'chartType', value:'2'}
			]
		},{
			xtype:'combobox',
			label:'combobox',
			displayField: 'value',
			valueField: 'id',
			allowBlank: false,
			data: [{id: 1, value: 'javascript1'}, {id: 0, value: 'javascript2'}],
			name:'holdData'
		},{
			xtype: 'button',
			iconCls: 'icon-plus',
			style: {
				'float': 'left'
			},
			label: 'button',
			handler: function() {
				
			}
		}]
	}],
	drag: true,
	bodyPadding: 0,
	columnHeight: 40,
	style: {
		height: 350,
		width: 600
	},
	columns: [
		{text: 'company', width: 200, dataIndex: 'company', locked: true}, 
		{text: 'price', width: 125, dataIndex: 'price', renderer: price},
		{text: 'change', width: 125, dataIndex: 'change', renderer: change},
		{text: 'pctChange', width: 125, dataIndex: 'pctChange', renderer: pctChange},
		{text: 'lastChange', width: 135, dataIndex: 'lastChange', renderer: lastChange}
	],
	store:store
});

grid.show('body');

表格分页演示。

var grid = Design.widget('grid', {
	title: {
		text: 'grid'
	},
	bodyPadding: 0,
	columnHeight: 40,
	style: {
		height: 350,
		width: 600
	},
	columns: [
		{text: 'company', width: 200, dataIndex: 'company', locked: true}, 
		{text: 'price', width: 125, dataIndex: 'price', locked: true, renderer: price},
		{text: 'change', width: 125, dataIndex: 'change', renderer: change},
		{text: 'pctChange', width: 125, dataIndex: 'pctChange', renderer: pctChange},
		{text: 'lastChange', width: 135, dataIndex: 'lastChange', renderer: lastChange}
	],
	store:store,
	drag: true,
	toolbar: [{
		dock: 'bottom',
		items: [{
			xtype: 'pagination',
			store: store,
			style: {
				float: 'right'
			}
		}]
	}]
});
grid.show();

表单演示1. 下面的form中日期控件扩展自jquery的 jscal2  日期控件。


var form = Design.widget('form', {
	style:{
		width: 400,
		height: 550
	},
	drag: true,
	title: {
		text: 'form'
	},
	bodyPadding: 30,
	fieldDefaults: {
		labelWidth: 50,
		fieldStyle:{
			width: 280
		}
	},
	items: [{
		xtype:'textfield',
		id: 'name',
		label:'姓名',
		allowBlank: false,
		name:'name'
	},{
		xtype:'combobox',
		label:'性别',
		displayField: 'value',
		valueField: 'id',
		allowBlank: false,
		data: [{id: 1, value: '男'}, {id: 0, value: '女'}],
		name:'holdData'
	},{
		xtype:'datefield',
		id: 'date',
		label:'日期',
		allowBlank: false,
		name:'name'
	},{
		xtype:'fieldcontainer',
		label:'电话',
		items:[
			{xtype:'displayfield',value:'(',fieldStyle:{'padding-right':'5px'}},
			{xtype:'textfield',labelWidth:0,fieldStyle:{width:'23px'}},
			{xtype:'displayfield',value:')',fieldStyle:{'padding-left':'5px','padding-right':'5px'}},
			{xtype:'textfield',labelWidth:0,fieldStyle:{width:'30px'}},
			{xtype:'displayfield',value:'-',fieldStyle:{'padding-left':'5px','padding-right':'5px'}},
			{xtype:'textfield',labelWidth:0,fieldStyle:{width:'30px'}
		}]
	},{
		xtype:'textareafield',
		label:'备注',
		name:'name'
	},{
		xtype:'fieldset',
		title:'选填内容',
		items:[{
			xtype:'fieldcontainer',
			label:'爱好',
			labelWidth: 50,
			fieldStyle:{
				width:185,
				height:100
			},
			items:(function(){
				var items = [{
					xtype:'radio',
					name:'color',
					fieldStyle:{
						width:70
					},
					boxLabel:'美工'
				}]
				for(var i=0;i<10;i++){
					items.push({
						xtype:'radio',
						name:'color',
						fieldStyle:{
							width:70
						},
						boxLabel:'码农'
					})
				}
				return items
			})()
		},{
			xtype:'textfield',
			label:'姓名',
			labelWidth: 50,
			fieldStyle:{
				width:'185'
			}
		},{
			xtype:'fieldcontainer',
			label:'宠物',
			items:[{
				xtype:'checkbox',
				boxLabel:'dog'
			},{
				xtype:'checkbox',
				boxLabel:'cat'
			}]
		}]
	}],
	buttons: [{
		text: '确定',
		handler: function() {
			var name = Design.getCmp('name');
			alert(name.getValue());
			//alert('ff');
		}
	}, {
		text: '取消',
		handler: function() {
			alert('cancel');
		}
	}]
});




form.show();

表单演示2.

var form = Design.widget('form', {
	style:{
		width: 605,
		height: 350
	},
	drag: true,
	title: {
		text: 'fieldcontainer'
	},
	bodyPadding: 15,
	fieldDefaults: {
		labelWidth: 100,
		fieldStyle:{
			width: 282
		}
	},
	items: [{
		xtype:'textfield',
		label:'Email Address',
		allowBlank: false,
		name:'email',
		fieldStyle:{
			width: 460
		}
	},{
		xtype:'fieldcontainer',
		label:'Date Range',
		items:[
			{xtype:'datefield',name: 'startDate', labelWidth:0, allowBlank: false, fieldStyle:{width:'224px'}},
			{xtype:'datefield',name: 'endDate', labelWidth:10, allowBlank: false, fieldStyle:{width:'224px'}}
		]
	},{
		xtype:'fieldset',
		title:'Details',
		items:[{
			xtype:'fieldcontainer',
			label:'phone',
			labelWidth: 100,
			items:[
				{xtype:'displayfield',value:'(',fieldStyle:{'padding-right':'5px'}},
				{xtype:'textfield',labelWidth:0,fieldStyle:{width:'23px'}},
				{xtype:'displayfield',value:')',fieldStyle:{'padding-left':'5px','padding-right':'5px'}},
				{xtype:'textfield',labelWidth:0,fieldStyle:{width:'30px'}},
				{xtype:'displayfield',value:'-',fieldStyle:{'padding-left':'5px','padding-right':'5px'}},
				{xtype:'textfield',labelWidth:0,fieldStyle:{width:'30px'}
			}]
		},{
			xtype:'fieldcontainer',
			label:'Time worked',
			labelWidth: 100,
			items:[
				{xtype:'textfield',name: 'hours', labelWidth:0,fieldStyle:{width:'35px'}},
				{xtype:'displayfield',value:'hours',fieldStyle:{'padding-right':'1px'}},
				{xtype:'textfield',name: 'mins', fieldStyle:{width:'35px'}},
				{xtype:'displayfield',value:'mins',fieldStyle:{'padding-right':'1px'}}
			]
		},{
			xtype:'fieldcontainer',
			label:'Full Name',
			labelWidth: 100,
			
			items:[
				{xtype:'combobox',name: 'hours', labelWidth:0,fieldStyle:{width:'55px'},value: 'mrs', displayField: 'name', valueField: 'value', data: [{name: 'Mr', value: 'mr'},{name: 'Mrs',  value: 'mrs'}, {name: 'Miss', value: 'miss'}]},
				{xtype: 'textfield', name : 'firstName', labelWidth:10,  allowBlank: false, fieldStyle:{width:'180px'}},
				{xtype: 'textfield', name : 'lastName', labelWidth:10,  allowBlank: false, fieldStyle:{width:'180px'}}
			]
		}]
	}],
	buttons: [{
		text: 'Save',
		handler: function() {
			alert('ff');
		}
	}, {
		text: 'Cancel',
		handler: function() {
			alert('cancel');
		}
	}]
});




form.show();

表单演示3.

var form = Design.widget('form', {
	style:{
		width: 406,
		height: 460
	},
	drag: true,
	title: {
		text: 'fieldcontainer'
	},
	bodyPadding: 15,
	fieldDefaults: {
		labelWidth: 100,
		fieldStyle:{
			width: 180
		},
		labelStyle: {
			'font-weight':'bold',
			'padding':'0'
		},
		labelAlign: 'top'
	},
	items: [{
		xtype:'fieldcontainer',
		label:'Your Name',
		labelWidth: 100,
		fieldDefaults: {
			labelWidth: 50,
			fieldStyle:{
				width: 110
			}
		},
		items:[{
			xtype: 'textfield',
			name: 'firstName',
			labelAlign: 'top',
			label: 'First',
			allowBlank: false
		}, {
			xtype: 'textfield',
			labelAlign: 'top',
			name: 'middleInitial',
			label: 'MI',
			labelWidth: 30,
			fieldStyle:{
				width: 30
			},
			style:{
				'margin-left': '10px',
				'margin-right': '10px'
			}
		}, {
			xtype: 'textfield',
			name: 'lastName',
			labelAlign: 'top',
			label: 'Last',
			allowBlank: false,
			fieldStyle:{
				width: 200
			}
		}]
	},{
		xtype: 'textfield',
		name: 'firstName',
		vtype: 'email',
		label: 'Your Email Address',
		allowBlank: false,
		fieldStyle:{
			width: 364
		}
	}, {
		xtype: 'textfield',
		label: 'Subject',
		allowBlank: false,
		fieldStyle:{
			width: 364
		}
	}, {
		xtype: 'textareafield',
		label: 'Message',
		allowBlank: false,
		fieldStyle:{
			width: 364,
			height: 130
		}
	}],
	buttons: [{
		text: 'Save',
		handler: function() {
			alert('ff');
		}
	}, {
		text: 'Cancel',
		handler: function() {
			alert('cancel');
		}
	}]
});




form.show();

   组合功能表格与表单交互。


var grid = Design.widget('panel', {
	title: {
		text: 'grid'
	},
	style: {
		height: 550,
		width: 900
	},
	bodyStyle: {
		overflow: 'hidden'
	},
	drag: true,
	items: [{
		xtype: 'grid',
		bodyPadding: 0,
		columnHeight: 40,
		onItemSelect: function(models, event) {
			//alert('')
			Design.getCmp('form').setModel(models[0]);
		},
		stripeRows: true,
		style: {
			height: '100%',
			width: "60%",
			float: 'left'
		},
		columns: [
			{text: 'company', width: 200, dataIndex: 'company', locked: true}, 
			{text: 'price', width: 125, dataIndex: 'price', renderer: price},
			{text: 'change', width: 125, dataIndex: 'change', renderer: change},
			{text: 'pctChange', width: 125, dataIndex: 'pctChange', renderer: pctChange},
			{text: 'lastChange', width: 135, dataIndex: 'lastChange', renderer: lastChange},
			{text: 'rating', width: 135, dataIndex: 'rating', renderer: rating}
		],
		store:store
	},{
		xtype: 'form',
		id: 'form',
		items: [{
			xtype: 'fieldset',
			title: 'Company details',
			fieldDefaults: {
				labelWidth: '100'
			},
			items: [{
				xtype: 'textfield',
				label: 'Name',
				name: 'company'
			},{
				xtype: 'textfield',
				label: 'Price',
				name: 'price'
			},{
				xtype: 'textfield',
				label: '% Change',
				name: 'pctChange'
			},{
				xtype: 'datefield',
				label: 'Last Updated',
				name: 'lastChange'
			}, {
				xtype: 'fieldcontainer',
				label: 'Rating',
				fieldDefaults: {
					name: 'rating', 
					xtype: 'radio'
				},
				items: [{
					value: '0',
					boxLabel: 'A'
				}, {
					value: '1',
					boxLabel: 'B'
				}, {
					value: '2',
					boxLabel: 'C'
				}]
			}]
		}],
		style: {
			width: '40%',
			height: '100%',
			float: 'left'
		}
	}]
});

grid.show('body');

树列表例子 下面的树扩展自jquery的zTree插件


var tree = Design.widget('tree',{
	title: {
		text: 'tree'
	},
	drag: true,
	style: {
		width: 300,
		height: 500,
		'float': 'left'	
	},
	bodyStyle: {
		overflow: 'auto'
	},
	datas: jsonData
});

tree.show('body');

选项卡例子。


var tree = Design.widget('tabpanel',{
	title: {
		text: 'tree'
	},
	drag: true,
	style: {
		width: 600,
		height: 500
	},
	items: [{
		xtype: 'panel',
		style: {
			width: '100%',
			height: '100%'
		},
		html: '<h1>panel1</h1>',
		title: {
			text: 'panel1'
		}
	},{
		xtype: 'panel',
		style: {
			width: '100%',
			height: '100%'
		},
		html: '<h1>panel2</h1>',
		title: {
			text: 'panel2'
		}
	},{
		xtype: 'panel',
		style: {
			width: '100%',
			height: '100%'
		},
		html: '<h1>panel3</h1>',
		title: {
			text: 'panel3'
		}
	}]
});

tree.show('body');


图表演示下面图表扩展自javascript highcharts 插件。

Design.Loader.setPath('Design', '../../src');
Design.require(['Design.chart.Chart']); 

var data = [['第一季度', 20],['第二季度', 20],['第三季度', 20],['第四季度', 20],['第五季度', 20]];

Design.onReady(function(){
	
	var chart = Design.widget('chart', {
		title: {
			text: 'chart'
		},
		drag: true,
		style: {
			width: 500,
			height: 500,
			'float': 'left'	
		}
	});
	chart.show('body');
	chart.setPieChart(data, '营业额');
});	

代码下载:

http://download.csdn.net/detail/junjun16818/5108310

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值