最近看到extjs的类桌面系统,被其界面吸引,然后试着用extjs desktop开发了一个项目。
一》开发目录结构:
resources文件夹是我们自己定义的放资源文件,包括样式,壁纸,图片等。
modules是我项目中对应的各个窗口js模块,也是我们自己需要开发的窗口模块。
extjslib是extjs的库文件;
extjslib中core文件夹内是desktop类桌面需要的模板js类,我们也可以自己开发这种界面,或者直接调用这些类。看名字应该知道这些类的作用
css是放的extjs的默认样式与desktop的样式
ext文件是extjs的函数库跟国际化文件
images是css需要引用的图片资料
下面直接讲开发代码
首先是index.html
Fly
/*!
* Ext JS Library 4.0
* [email protected]
*/
Ext.define('FlyDesktop.App', {
extend: 'Ext.ux.desktop.App',
//引用我们自己定义的模块
requires: [
'Ext.ux.desktop.ShortcutModel',
'Fly.modules.SystemStatus',
'Fly.modules.Users',
'Fly.modules.BaseSetup',
'Fly.modules.HomeView',
'Fly.modules.StateCurve',
'Fly.modules.Settings'
],
init: function() {
this.callParent();
},
//调用模块的方法,这里必须需要
getModules : function(){
return [
new Fly.modules.SystemStatus(), //因为最开始在index.html中Ext.Loader.setConfig({enabled:true});
//同时又命令了'Fly.modules': 'modules'的空间,所以这句话其实就是调用modules下的SystemStatus.js。
new Fly.modules.Users(), //同上
new Fly.modules.HomeView(), //同上
new Fly.modules.StateCurve(), //同上
new Fly.modules.BaseSetup() //同上
];
},
getDesktopConfig: function () {
var me = this, ret = me.callParent();
// 如果这里不注释掉的话,我们可以去掉core文件夹中ShortcutModel.js,
// 其实那个文件也只封装了一个model而已,同时上面的requires就不需要引用了
// Ext.define('Ext.ux.desktop.ShortcutModel', {
// extend: 'Ext.data.Model',
// fields: [{
// name: 'name'
// },{
// name: 'iconCls'
// },{
// name: 'module'
// }]
// });
return Ext.apply(ret, {
contextMenuItems: [{ //鼠标右键的设置
text: '壁纸设置',
handler: me.onSettings, //响应函数
scope: me
},{
text: '样式设置',
handler: me.onCssSettings, //响应函数
scope: me
}],
shortcuts: Ext.create('Ext.data.Store', {
model: 'Ext.ux.desktop.ShortcutModel',
data: [{
name: 'xx管理',
iconCls: 'XXCSS',
module: 'users' //这个参数就是自己所开发的模块的id,这个是必须的
},{
name: 'xx配置',
iconCls: 'XXCSS',
module: 'XXX'
},{
name: 'xx界面',
iconCls: 'XXCSS',
module: 'XXX'
},{
name: 'xx状态',
iconCls: 'XXCSS',
module: 'XXX'
},{
name: 'xx配置',
iconCls: 'XXCSS'
},{
name: 'xx曲线',
iconCls: 'XXXCSS',
module: 'XXX'
}]
}),
wallpaper: 'resources/wallpapers/创意.jpg', //这里是初始化壁纸的路径
wallpaperStretch: true //初始化壁纸是否被拉伸
});
},
// config for the start menu
getStartConfig : function() { //开始菜单的设置(右边导航栏)
var me = this, ret = me.callParent();
return Ext.apply(ret, {
title: '导航栏',
iconCls: 'user',
height: 300,
toolConfig: {
width: 100,
items: [{
text:'设置',
iconCls:'settings',
handler: me.onSettings,
scope: me
},'-',{
text:'退出',
iconCls:'logout',
handler: me.onLogout,
scope: me
}]
}
});
},
getTaskbarConfig: function () { //快速启动栏的设置
var ret = this.callParent();
return Ext.apply(ret, {
quickStart: [{
name: 'XX配置',
iconCls: 'accordion',
module: 'XXX' //参数是自己开发模块的id
},{
name: 'XX界面',
iconCls: 'icon-grid',
module: 'XXX'
}],
trayItems: [{
xtype: 'trayclock', //这个是快捷栏右边的时间组件,是定义在TaskBar.js中的Ext.ux.desktop.TrayClock类。
//这个很简单,只要懂extjs就明白
flex: 1
}]
});
},
onLogout: function () { //退出系统的操作
Ext.Msg.confirm('退出', '确认退出系统?',function(button){
if(button=="yes"){
Ext.Ajax.request({
url: 'logout.shtml',
method:'POST',
success: function (data) {
if (typeof data == 'object') {
var redata = Ext.decode(data.responseText);
alert(redata.msg);
Ext.util.Cookies.clear('Fly');
console.log(Ext.util.Cookies.get('Fly'));
window.location = window.location.pathname+"login.html";
}
}
});
}
});
},
onSettings: function () { //设置壁纸的操作
var dlg = new Fly.modules.Settings({ //这里Fly.modules.Settings是自己写的类。另有详细解释
desktop: this.desktop
});
dlg.show();
},
onCssSettings: function () {
Ext.create("Ext.window.Window",{
title:'样式设置',
modal: true,
width: 640,
height: 480,
border: false,
layout:'fit'
}).show();
}
});
这个类就是我们在modules中自己定义的Setting.js,这个 类可以当作desktop的系统类放入到core中,我因为在这里做了其他的配置操作,比如样式的控制,桌面图标的自定义排列,所以作为了一个自定义的模块。
/*!
* Ext JS Library 4.0
* Copyright(c) 2006-2011 Sencha Inc.
* [email protected]
* http://www.sencha.com/license
*/
Ext.define('Fly.modules.Settings', {
extend: 'Ext.window.Window',
uses: [
'Ext.tree.Panel',
'Ext.tree.View',
'Ext.form.field.Checkbox',
'Ext.layout.container.Anchor',
'Ext.layout.container.Border',
'Ext.ux.desktop.Wallpaper'
],
layout: 'anchor',
title: '壁纸设置',
modal: true,
width: 640,
height: 480,
border: false,
initComponent: function () {
var me = this;
Ext.define('WallpaperModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'text'
},{
name: 'img'
}]
});
me.selected = me.desktop.getWallpaper();
me.stretch = me.desktop.wallpaper.stretch;
me.preview = Ext.create('widget.wallpaper'); //调用extjs中core中的壁纸模板类
me.preview.setWallpaper(me.selected);
me.tree = me.createTree();
me.buttons = [
{
text: '确定',
handler: me.onOK,
scope: me
},
{
text: '取消',
handler: me.close,
scope: me
}
];
me.items = [
{
anchor: '0 -30',
border: false,
layout: 'border',
items: [
me.tree,
{
xtype: 'panel',
title: '预览',
region: 'center',
layout: 'fit',
items: [ me.preview ]
}
]
},
{
xtype: 'checkbox',
boxLabel: '拉伸适合屏幕',
checked: me.stretch,
listeners: {
change: function (comp) {
me.stretch = comp.checked;
}
}
}
];
me.callParent();
},
createTree : function() {
var me = this;
function child (img) {
return {
img: img,
text: me.getTextOfWallpaper(img),
iconCls: '',
leaf: true
};
}
var tree = new Ext.tree.Panel({
title: '壁纸',
rootVisible: false,
lines: false,
autoScroll: true,
width: 150,
region: 'west',
split: true,
minWidth: 100,
listeners: {
afterrender: {
fn: this.setInitialSelection,
delay: 100
},
select: this.onSelect,
scope: this
},
store: new Ext.data.TreeStore({
model: 'WallpaperModel', //初始化壁纸
root: {
text:'壁纸',
expanded: true,
children:[
child('Win7.jpg'),
child('净土.jpg'),
child('创意.jpg'),
child('卡通.jpg'),
child('山水.jpg'),
child('幻境.jpg'),
child('幻想.jpg'),
child('梦想.jpg'),
child('水滴.jpg'),
child('祥和.jpg'),
child('雪地.jpg'),
child('战马.jpg'),
{
text: "None",
iconCls: '',
leaf: true
}]
}
})
});
return tree;
},
getTextOfWallpaper: function (path) {
var text = path, slash = path.lastIndexOf('/');
if (slash >= 0) {
text = text.substring(slash+1);
}
var dot = text.lastIndexOf('.');
text = Ext.String.capitalize(text.substring(0, dot));
text = text.replace(/[-]/g, ' ');
return text;
},
onOK: function () {
var me = this;
if (me.selected) {
me.desktop.setWallpaper(me.selected, me.stretch);
}
me.destroy();
},
onSelect: function (tree, record) {
var me = this;
if (record.data.img) { //指定壁纸的路径
me.selected = 'resources/wallpapers/' + record.data.img;
} else {
me.selected = Ext.BLANK_IMAGE_URL;
}
me.preview.setWallpaper(me.selected);
},
setInitialSelection: function () {
var s = this.desktop.getWallpaper();
if (s) {
var path = '/Wallpaper/' + this.getTextOfWallpaper(s);
this.tree.selectPath(path, 'text');
}
}
});
有了上面这几个部分 我们其实就可以构建一个桌面系统了
然后我插入一个自定义的模块功能Users.js
/*!
* Ext JS Library 4.0
* Copyright(c) 2006-2011 Sencha Inc.
* [email protected]
* http://www.sencha.com/license
*/
Ext.define('Fly.modules.Users', {
extend: 'Ext.ux.desktop.Module',
requires: [
'Ext.data.JsonStore',
'Ext.util.Format',
'Ext.grid.Panel',
'Ext.grid.RowNumberer'
],
id:'users',
init : function(){
this.launcher = {
text: '用户管理',
iconCls:'icon-grid'
};
},
createWindow : function(){
var desktop = this.app.getDesktop();
var win = desktop.getWindow('users-grid');
var required = '* ';
Ext.define('Fly.model.User', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type:'int'
},{
name: 'userName',
type:'string'
},{
name: 'userPasswd',
type:'password'
},{
name: 'userPermiss'
},{
name: 'description',
type:'string'
},{
name: 'logintimes',
type:'int'
}]
});
var userStore = Ext.create('Ext.data.Store', {
autoLoad: true,
autoDestroy: true,
storeId: 'userStore',
model:'Fly.model.User',
proxy: {
actionMethods:{
create: "POST",
read: "POST",
update: "POST",
destroy: "POST"
},
type: 'ajax',
api: {
create : 'user/adduser.shtml',
read : 'user/userslist.shtml',
update : 'user/updateuser.shtml',
destroy : 'user/delete.shtml'
},
reader: {
type: 'json',
root: 'rows',
idProperty: 'id'
}
}
});
//下拉框数据。
var cbstore = Ext.create('Ext.data.ArrayStore', {
autoDestroy : true,
fields: ['id', 'name'],
data : [[0,"管理员"],[1,"操作员"],[2,"浏览员"]]
});
Ext.apply(Ext.form.VTypes, {
confirmPwd : function(val, field) {
if (field.confirmPwd) {
var firstPwdId = field.confirmPwd.first;
var secondPwdId = field.confirmPwd.second;
this.firstField = Ext.getCmp(firstPwdId);
this.secondField = Ext.getCmp(secondPwdId);
var firstPwd = this.firstField.getValue();
var secondPwd = this.secondField.getValue();
if (firstPwd == secondPwd) {
return true;
} else {
return false;
}
}
},
confirmPwdText : '两次输入的密码不一致!'
});
if(!win){
var userid;
var usergrid = Ext.create('Ext.grid.Panel',{
flex:2,
frame: true,
title:'用户列表',
store: userStore,
layout: 'column',
columns: [
new Ext.grid.RowNumberer(),
{
text: "ID",
flex: 1,
dataIndex: 'id'
},{
text: "用户名",
flex: 2,
dataIndex: 'userName'
},{
text: "权限",
flex: 1,
dataIndex: 'userPermiss',
renderer:function(v){
if (v == 0) return "管理员";
if (v == 1) return "操作员";
if (v == 2) return "浏览员";
}
},{
text: "描述",
flex: 3,
dataIndex: 'description'
},{
text: "登陆次数",
flex: 1,
dataIndex: 'logintimes'
}],
listeners: {
selectionchange: function(model, records) {
if (records[0]) {
userid = records[0].data.id;
Ext.getCmp('userForm').loadRecord(records[0]);
Ext.getCmp('user_save').setDisabled(false);
Ext.getCmp('userForm').remove('reUserPasswd');
Ext.getCmp('user_update').setDisabled(false);
Ext.getCmp('user_delete').setDisabled(false);
Ext.getCmp('user_save').setText('增加');
}
}
}
});
var userform = Ext.widget({
flex:1,
title:'用户编辑',
xtype: 'form',
frame: true,
id: 'userForm',
bodyPadding: 10,
layout:'anchor',
fieldDefaults: {
labelStyle:'font-weight: bold;text-align:right',
labelWidth: 70
},
defaultType: 'textfield',
items: [{
id:'user-name',
fieldLabel: '用户名',
beforeLabelTextTpl: required,
name: 'userName',
allowBlank:false,
enableKeyEvents: true,
listeners:{
//事件监听,当用户离开输入框——失去焦点时执行
'blur':function(){
Ext.Ajax.request({
url:'checkname.shtml?loginName='+Ext.getCmp('user-name').getValue(),
method:'post',
success: function(response,opts){
var respText=Ext.decode(response.responseText);
if(respText.success == true){
//根据ajax请求返回的数据信息手动的进行设置该字段无效
Ext.getCmp('user-name').markInvalid('该用户名已被使用');
}
}
});
}
}
},{
fieldLabel: '类型',
beforeLabelTextTpl: required,
xtype: 'combobox',
store: cbstore,
displayField: 'name',
valueField: 'id',
name: 'userPermiss',
forceSelection:true,
allowBlank:false
},{
fieldLabel: '描述',
name: 'description',
xtype:'textarea'
},{
id:'password',
fieldLabel: '密码',
beforeLabelTextTpl: required,
name: 'userPasswd',
blankText : '密码不能为空',
regex : /^[\s\S]{6,32}$/,
regexText : '密码长度必须大于6小于32',
inputType : 'password',
allowBlank:false
}],
buttons: [{
id:'user_save',
text: '增加',
maxWidth:55,
handler:function(){
var user_form = this.up('form');
if(this.getText() == '增加'){
if(!Ext.get('reUserPasswd')){
user_form.add({
id:'reUserPasswd',
name:'reUserPasswd',
fieldLabel: '确认密码',
beforeLabelTextTpl: required,
confirmPwd : {
first : 'password',
second : 'reUserPasswd'
},
inputType : 'password',
vtype : 'confirmPwd',
regex : /^[\s\S]{6,32}$/,
regexText : '密码长度必须大于6小于32',
allowBlank:false
})
}
user_form.getForm().reset();
Ext.getCmp('user_update').setDisabled(true);
Ext.getCmp('user_delete').setDisabled(true);
this.setText('保存');
}else{
if(user_form.getForm().isValid()){
user_form.getForm().submit({
url: 'user/adduser.shtml',
submitEmptyText: false,
waitTitle:'请等待',
waitMsg: '正在添加用户...',
success:function(form,action){
var response = Ext.decode(action.response.responseText);
Ext.Msg.alert('提示', response.msg);
userStore.load();
},
failure:function(form,action){
Ext.Msg.alert('提示', '添加用户失败!');
}
});
}else{
Ext.Msg.alert('提示', '数据验证失败!');
}
this.setText('增加');
Ext.getCmp('userForm').remove('reUserPasswd');
Ext.getCmp('user_update').setDisabled(false);
Ext.getCmp('user_delete').setDisabled(false);
}
}
},{
id:'user_update',
text: '编辑',
maxWidth:55,
handler:function(){
var user_form = this.up('form');
if(user_form.getForm().isValid()){
user_form.getForm().submit({
url: 'user/updateuser.shtml',
submitEmptyText: false,
waitTitle:'请等待',
waitMsg: '正在编辑用户...',
params : {
id : userid
},
success:function(form,action){
var response = Ext.decode(action.response.responseText);
Ext.Msg.alert('提示', response.msg);
userStore.load();
},
failure:function(form,action){
Ext.Msg.alert('提示', '编辑用户失败!');
}
});
}else{
Ext.Msg.alert('提示', '数据验证失败!');
}
}
},{
id:'user_delete',
text: '删除',
maxWidth:55,
handler: function() {
Ext.Ajax.request({
url:'user/delete.shtml?ids='+userid,
method:'post',
waitTitle:'请等待',
waitMsg: '正在删除用户...',
params : {
id : userid
},
success:function(response,opts){
var respText=Ext.decode(response.responseText);
if(respText.success == true){
Ext.Msg.alert('提示', respText.msg);
userStore.load();
}
},
failure:function(form,action){
Ext.Msg.alert('提示', '删除用户失败!');
}
});
}
},{
text: '取消',
maxWidth:55,
handler: function() {
this.up('form').getForm().reset();
}
}]
});
win = desktop.createWindow({
id: 'users-grid',
title:'用户管理',
width:800,
height:500,
iconCls: 'icon-grid',
layout: {
type: 'hbox',
align: 'stretch',
defaultMargins:{
top: 1,
right: 1,
bottom: 1,
left: 1
},
padding:0
},
items: [
usergrid,
userform
]
});
}
return win;
}
});
id:'users',
就是前面module参数需要引用的。
最后一点是,如果想在一个窗口中调用另一个窗口,可以使用下面的方法:
比如我们点击一个窗口中的按钮,想打开另一个窗口
xtype:'button',
handler:function(){
var module = me.app.getModule('#另一个窗口的ID'),
win = module && module.createWindow();
if (win) {
if (win.isVisible()) {
win.restore();
win.toFront();
} else {
win.show();
}
return win;
}
}