在没接触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