Extjs复习之管理后台的通用模版

很久没有用过ExtJS,正好一个新的在线系统需要搭建一个运营平台,没有交互,没有页面设计,没有原型,我那点可怜的美感只能借助Extjs来搭建了。

1.通用的架子典型的Border布局+tree菜单+TabPanel的内容区的框架,模块清晰简单,菜单可配置。

			Ext.BLANK_IMAGE_URL="ext/resources/images/default/s.gif";
			Ext.QuickTips.init();   
			/*菜单面板*/
			MenuPanel=function(config){
				config=config||{};
				var config_=Ext.applyIf({
					layout:'accordion',
					region:'west',
					split:true,
					width:200,
					collapsible:true,
					border:false,
					animate: true
				},config);
				MenuPanel.superclass.constructor.call(this,config_);
			};
			Ext.extend(MenuPanel,Ext.Panel,{});
			
			/*菜单模块面板*/
			ModulePanel=function(config){
					config=config||{};
					var nodes_loader=new Ext.tree.TreeLoader({dataUrl:config.dataUrl});
					ModulePanel.superclass.constructor.call(this,{
						animate: true,
						title:config.title,
						rootVisible:false,
						iconCls:'tab_icon',
						region:'west',
						split:true,
						width:200,
						collapsible:true,
						root:{
						},
						loader:nodes_loader
					});
			};
			
			Ext.extend(ModulePanel,Ext.tree.TreePanel,{
				setTargetOpen:function(contentPanel){
						this.on("click",function(node){
							if(!node.attributes.leaf){
								return true;
							}
							var tabid="module_tab_"+node.attributes.id;
							var exist_panel=contentPanel.getComponent(tabid);
							if(exist_panel){
								contentPanel.setActiveTab(exist_panel);
							}else{
								var iframe_in_tab="iframe_"+tabid;
								var iframe_html="<iframe width=100% height=100% id='"+iframe_in_tab+"'/>"
								var panel=new Ext.Panel({
									title:node.attributes.text,
									id:tabid,
									closable:true,
									iconCls:'tab_icon_2',
									html:iframe_html
								});
								contentPanel.add(panel);
								contentPanel.setActiveTab(panel);
								Ext.get(iframe_in_tab).set({
									src:node.attributes.url
								});
							}
						});
				}
			});
			
			/*主面板*/
			MainPanel=function(){
					MainPanel.superclass.constructor.call(this,{
						region:'center',
						margins:'0 5 5 0',
				        resizeTabs: true,
				        minTabWidth: 135,
				        tabWidth: 135,
				        enableTabScroll: true,
				        activeTab: 0,
				        items:[{
				        	title:'公告面板',
				        	closable:true,
				        	html:'管理平台欢迎您,如有问题,请联系coreycui,timwen,liubangchen'
				        }],
				        tbar:new Ext.Toolbar({
				        	items:[
				        	    {xtype:'displayfield',value:'内容页面导航: ',style:'color:RED'},
				        		{xtype:'button',iconCls:'prev_icon',tooltip:'后退',handler:function(){
                                    var activePanel=this.findParentByType("toolbar",false).ownerCt.getActiveTab();
                                    var activePanelId=activePanel.getItemId();
									var iframe_in_tab=Ext.get("iframe_"+activePanelId);
									Ext.getDom("iframe_"+activePanelId).contentWindow.history.back();
				        		}},   
				        		{xtype:'button',iconCls:'next_icon',tooltip:'前进',handler:function(){
                                    var activePanel=this.findParentByType("toolbar",false).ownerCt.getActiveTab();
                                    var activePanelId=activePanel.getItemId();
									var iframe_in_tab=Ext.get("iframe_"+activePanelId);
									Ext.getDom("iframe_"+activePanelId).contentWindow.history.forward();
				        		}},
				        		{xtype:'button',iconCls:'refresh_icon',tooltip:'刷新',handler:function(){
                                    var activePanel=this.findParentByType("toolbar",false).ownerCt.getActiveTab();
                                    var activePanelId=activePanel.getItemId();
									var iframe_in_tab=Ext.get("iframe_"+activePanelId);
									Ext.getDom("iframe_"+activePanelId).contentWindow.document.location.reload();
				        		}}
				        	]
				        })
					});
			}
			Ext.extend(MainPanel,Ext.TabPanel,{});
			
			Ext.onReady(function(){
				var contentPanel=new MainPanel();
				
				
				var menu_panel=new ModulePanel({
					title:'功能导航',
					dataUrl:'menu_node.jsp'
					
				});
				
				menu_panel.setTargetOpen(contentPanel);
				
				
				var viewport=new Ext.Viewport({
					layout:'border',
					items:[
						{region:'north',border:false,contentEl:'header',split:true},
						menu_panel,
						contentPanel
					]
				});
			});

菜单控制基于另外的一个json页面,可方便的接入权限控制,配置如下:
[
	{
		text:'直通车',children:[
			{text:'a1',leaf:true,url:'http://com/g/s?aid=index&g_ut=1',id:'a1'},
			{text:'a2',leaf:true,url:'http://com/g/s?aid=index&g_ut=2',id:'a2'},
			{text:'a3',leaf:true,url:'http://.com',id:'a3'},
			{text:'a4',leaf:true,url:'http://com',id:'a4'},
			{text:'a5',leaf:true,url:'http://0',id:'a5'},
			{text:'a6',leaf:true,url:'http://a1p',id:'a6'}
		]
	},
	{
		text:'XX管理',children:[
			{text:'XX查询',leaf:true,url:'<%=request.getContextPath()%>/xxmanage/querycp.jsp',id:'xx_query'},
			{text:'XX审核',leaf:true,url:'<%=request.getContextPath()%>/xxmanage/querycp4manage.jsp',id:'xx_manage'} 
		]
	}
]

为了防止内存泄漏和全局变量泛滥,采用继承和组合的方式来组织整个页面的UI结构。继承的模式大致如下:
			MenuPanel=function(config){
				config=config||{};
				var config_=Ext.applyIf({
					layout:'accordion',
					region:'west',
					split:true,
					width:200,
					collapsible:true,
					border:false,
					animate: true
				},config);
				MenuPanel.superclass.constructor.call(this,config_);
			};
			Ext.extend(MenuPanel,Ext.Panel,{});


MenuPanel.superclass.constructor.call(this,config_);

主要用来在子类的构造函数里面显示的调用父类的构造函数。
var config_=Ext.applyIf();
主要用来指定一些固定的初始化option

2.Grid模块
var columnModel=new Ext.grid.ColumnModel([
					        {header:'日期',dataIndex:'stat_date'}
						/*............*/
				]);
				
				var grid=new Ext.grid.GridPanel({
					cm:columnModel,
					store:store,
					renderTo:'grid',
					autoHeight:true,
					viewConfig:{
						forceFit:true
					},
					loadMask:{
						msg:'不要着急,休息一下,休息一下 :)..'
					},
					bbar:new Ext.PagingToolbar({
						pageSize:10,
						store:store,
						stripeRows:true,
						displayInfo:true,
						displayMsg:'显示第{0}条到第{1}条,一共{2}条',
						emptyMsg:'无记录'
					})
				});
				
				var form=new Ext.form.FormPanel({
					renderTo:'data_setting_div',
					labelAlign:'right',
					labelWidth:60,
					items:[
						{
							xtype: 'compositefield',
			                fieldLabel: '日期范围',
			                defaults:{
			                	width:150
			                },
							items:[
								{xtype:'datefield',id:'startdate',name:'startdate'},
								{xtype:'displayfield',value:'--',width:10},
								{xtype:'datefield',name:'enddate',id:'enddate'},
								{xtype:'button',text:'查询',listeners:{
									click:function(){
										startDate=form.getForm().findField("startdate").getValue().format('Y-m-d')
										endDate=form.getForm().findField("enddate").getValue().format('Y-m-d');
										store.reload();
									}
								}}
							]
						}
				   ]
				});
				store.load({params:{start:0, limit:10,fromButton:'refresh'}});

强制单元格填充表格:
                                        viewConfig:{
						forceFit:true
					}

第一次渲染grid的时候必须显示load store,并且需要指定start和limit这两个分页参数,store不会去自动取在grid中配置的。
store.load({params:{start:0, limit:10,fromButton:'refresh'}});

如果需要查询条件:
								{xtype:'button',text:'查询',listeners:{
									click:function(){
										startDate=form.getForm().findField("startdate").getValue().format('Y-m-d')
										endDate=form.getForm().findField("enddate").getValue().format('Y-m-d');
										store.reload();
									}
								}}
还必须添加以下事件:
                                 var store=new Ext.data.Store({
					proxy:new Ext.data.HttpProxy({
						url:gridDataUrl
					}),
					reader:new Ext.data.JsonReader({
						totalProperty: 'totalCount',
						root:'list'
					},[
						{name:'stat_date'}
						/*{}*/
					]),
					listeners:{
						beforeload:function(thiz,options){
							 Ext.apply 
				             ( 
				            	 thiz.lastOptions.params,   
				                 {  
				                     startDate : startDate,  
				                     endDate : endDate
				                 } 
				             );
						}
					}
				});

thiz.lastOptions.params
代表最后提交的参数。


3.扩展Extjs HTMLEditor,图片文件上传并插入。
Extjs HTML Editor是比较坑爹的,自己扩展了一个图片插入的组件。使用方式如下:
                                                                       new Ext.form.HtmlEditor({
										fieldLabel:'正文',
										id:'news_details',
										name:'news_details',
										plugins:new FileInsertPlugin({url:FileUpload.url,MVC_BUS:'FileManager',MVC_ACTION:'upload'})
									}),


FileInsertPlugin:
       /*coreycui*/
       FileInsertPlugin = function(config) {
		config=config||{};
		var editor;
		var win;
		/*创建图片*/
		var createImage = function() {
			var imageWidth = win.getImageWidth();
			var imageHeight = win.getImageHeight();
			var element = document.createElement("img");
			element.src = win.getImageSrc();
			element.alt = win.getImageAlt();
			if (imageWidth == null || imageWidth == '') {
			} else {
				element.style.width = imageWidth + "px"
			}
			if (imageHeight == null || imageHeight == '') {
			} else {
				element.style.height = imageHeight + "px"
			}
			return element;
		}
		
		// 把图片插入editor中
		var insertImageByBrowser = function() {
			if (Ext.isIE) {
				return function() {
					var selection = editor.doc.selection;
					var range = selection.createRange();
					range.pasteHTML(createImage().outerHTML);
				};

			} else {
				return function() {
					var selection = editor.win.getSelection();
					if (!selection.isCollapsed) {
						selection.deleteFromDocument();
					}
					selection.getRangeAt(0).insertNode(createImage());
				};
			}
		}();
		
		/*插入图片*/
		var insertImage = function() {
			editor.win.focus();
			insertImageByBrowser();
			editor.updateToolbar();
			editor.deferFocus();
		};
		
		/*图片成功回调*/
		var whenImgUploadSuccess=function(result){
			insertImage();
			win.close();
		};
		/*图片失败回调*/
		var whenImgUploadFailure=function(result){
			Msg.MessageBox.alert("图片上传失败",result.msg);
			win.close();
		}
		
		/*打开图片上传窗口*/
		var openImageWindow = function() {
			win=new FileUploadWindow(config);
			win.setSuccessCallback(whenImgUploadSuccess);
			win.setFailureCallback(whenImgUploadFailure);
			win.show(this);
		}
		
		
		var onRender=function(){
			editor.tb.add({
				itemId : 'image',
				cls : 'x-btn-icon x-edit-image',
				handler : openImageWindow,
				tooltip : {
					title : '图片',
					text : '插入图片',
					cls : 'x-html-editor-tip'
				}
			});
		}
		return {
			init : function(htmlEditor) {
				editor = htmlEditor;
				editor.on('render',onRender); 
			}
		}
	}

插件的形式主要是在init中做文章,宿主会render后init这个插件:
                        init : function(htmlEditor) {
				editor = htmlEditor;
				editor.on('render',onRender); 
			}
主要是将生成的HTML代码插入在编辑器中:
                                        var selection = editor.doc.selection;
					var range = selection.createRange();
					range.pasteHTML(createImage().outerHTML);

文件上传的窗口如下:
/*文件上传窗口*/
FileUploadWindow=function(config){
        config=config||{};
        /*成功的回调函数*/
        var successCallback;
        var failureCallback;
        var fileUrl;
        var fileUploadForm=new Ext.form.FormPanel({
                        fileUpload:true,
                        url:config.url,
                        labelAlign:'right',
                        labelWidth:60,
                        defaults:{
                                anchor:'-20'
                        },      
                        items:[ 
                                {fieldLabel:'本地文件',xtype:'textfield',name:'file',id:'file',inputType:'file'},
                                {fieldLabel:'文件描述',xtype:'textfield',name:'filedesc',id:'filedesc',width:190},
                                {fieldLabel:'高度',xtype:'textfield',name:'fileheight',id:'fileheight',width:190},
                                {fieldLabel:'宽度',xtype:'textfield',name:'filewidth',id:'filewidth',width:190}
                        ],      
                        buttons:[
                                {text:'提交',handler:function(){
                                			fileUploadForm.getForm().submit({
                                			params:config,
                                			failure:function(form,action){
                                				if(failureCallback){
                                					failureCallback(action.result);
                                            	}
                                			},
                                			success:function(form,action){
                                				fileUrl=action.result.fileUrl;
                                            	if(successCallback){
                                            		successCallback(action.result);
                                            	}
                                            }
                                		});
                                }}      
                        ]       
        });     
        
        Ext.apply(config,{
                width:325,
                title:'图片插入',
                autoHeight:true,
                items:[fileUploadForm]
        });     
        FileUploadWindow.superclass.constructor.call(this,config);
        /*获取表单*/
        this.getForm=function(){
        	return fileUploadForm;
        }
        /*获取基础表单*/
        this.getBasicForm=function(){
        	return fileUploadForm.getForm();
        }
        /*设置成功回调函数*/
        this.setSuccessCallback=function(callbackfn){
        	successCallback=callbackfn;
        }
        /*设置失败回调函数*/
        this.setFailureCallback=function(callbackfn){
        	failureCallback=callbackfn;
        }
        this.getImageSrc=function(){
        	return fileUrl;
        }
        this.getImageAlt=function(){
        	return this.getBasicForm().findField('filedesc').getValue();
        }
        this.getImageWidth=function(){
        	return this.getBasicForm().findField('filewidth').getValue();
        }
        this.getImageHeight=function(){
        	return this.getBasicForm().findField('fileheight').getValue();
        }
}

Ext.extend(FileUploadWindow,Ext.Window,{});

事实上就是一个文件上传的扩展窗口,可以在初始化参数中指定文件上传的URL路径,将上传成功和失败的回调钩子的实现留给了调用者。向外提供了获取图片上传后的图片的属性。

4.一个增删改查的窗口抽取。
一个grid配上了一个用于增改的window。将window和grid的控制逻辑抽取出来,将window中的表单,记录新增的URL,记录修改的URL,记录内容获取的URL路径暴露出来。在grid的toolbar中新增如下功能按钮以及相对的数据:
                                                  tbar:new Ext.Toolbar({
							items:[
								{xtype:'button',text:'新增新闻',iconCls:'add',handler:function(thiz,option){
									var newsForm=new NewsForm(mvcUrl);
									var newsAddWin=new AddOrEditWindow({autoScroll:true,width:800,height:500,title:'新增新闻',mvcUrl:mvcUrl},newsForm)
									newsAddWin.show();
									newsAddWin.setParams({
										MVC_BUS:'News',
										MVC_ACTION:'add'
									});
									newsAddWin.setSuccessCallback(function(){
										store.reload();
									});
								}},
								
							       {xtype:'button',text:'编辑新闻',iconCls:'icon_window',handler:function(thiz,option){
								var selections=sm.getSelections();
								if(selections.length!=1){
									Ext.example.msg("警告","请选择一条记录!");
								}else{
									var id=selections[0].get("id");
									var newsForm=new NewsForm(mvcUrl);
									var newsAddWin=new AddOrEditWindow({autoScroll:true,width:800,height:500,title:'编辑新闻',mvcUrl:mvcUrl},newsForm)
									newsAddWin.show();
									newsAddWin.initFormData(config.getDataUrl,{id:id});
									newsAddWin.setParams({
										MVC_BUS:'News',
										MVC_ACTION:'edit'
									});
									newsAddWin.setSuccessCallback(function(){
										store.reload();
									});
								}
							}}
							]
						})

新增和修改的主要是玩转一个AddOrEditWindow,我们将自己构造的表单作为参数传入该window:
var newsAddWin=new AddOrEditWindow({autoScroll:true,width:800,height:500,title:'编辑新闻',mvcUrl:mvcUrl},newsForm)


当window用来编辑的时候,这个form还必须实现一个接口,obj是从记录获取URL中得到的数据对象,如下:
                                       this.setFields=function(obj){
						this.getForm().findField("news_title").setValue(obj.result.summary.news_title);
						this.getForm().findField("summary").setValue(obj.result.summary.summary);
						this.getForm().findField("status_combo").setValue(obj.result.summary.status);
						this.getForm().findField("news_order").setValue(obj.result.summary.news_order);
						editor.setSource(obj.result.details.news_details);
						if(obj.result.types){
							for(var i=0;i<obj.result.types.length;i++){
								var typeCheckboxId="news_type_"+obj.result.types[i];
								var checkBoxType=Ext.getCmp(typeCheckboxId);
								checkBoxType.setValue(true);
							}
						}
					}
调用
newsAddWin.initFormData(config.getDataUrl,{id:id});
系统会从第一个参数URL中用第二个param map去远程服务器获取一个obj数据对象。调用form的setFields进行填充,并且将id属性关联在该修改表单上。

AddOrEditWindow的实现如下:
AddOrEditWindow = function(config, form) {
	config = config || {};
	var thiz = this;
	var params = {};
	var successCallback;
	var failureCallback;
	var formPanel = form;
	var sumitForm = function() {
		formPanel.getForm().submit({
			params : params,
			success : function(form, action) {
				Ext.example.msg("提示", "操作成功");
				if (successCallback) {
					successCallback();
				}
				thiz.close();
			},
			failure : function(form, action) {
				Ext.example.msg("提示", "操作失败");
				if (failureCallback) {
					failureCallback();
				}
				thiz.close();
			}
		});
	}

	Ext.apply(config, {
		iconCls : 'icon_window',
		items : [ formPanel ],
		buttons : [ {
			xtype : 'button',
			text : '提交',
			iconCls : 'save',
			handler : function() {
				sumitForm();
			}
		}, {
			xtype : 'button',
			text : '关闭',
			iconCls : 'delete',
			handler : function() {
				thiz.close();
			}
		} ]
	});
	AddOrEditWindow.superclass.constructor.call(this, config);

	this.setParams = function(ps) {
		Ext.apply(params, ps);
	}

	this.initFormData = function(url, ps) {
		Ext.Ajax.request({
			url : url,
			params : ps,
			success : function(resp, options) {
				var respText = Ext.util.JSON.decode(resp.responseText);
				params.id = respText.result.id;
				formPanel.setFields(respText);
			},
			failure : function(resp, options) {
				thiz.close();
			}
		});
	}

	this.setSuccessCallback = function(fn) {
		successCallback = fn;
	}

	this.setFailureCallback = function(fn) {
		failureCallback = fn;
	}
};

Ext.extend(AddOrEditWindow, Ext.Window, {});


5.一些小技巧
给表格新增一个操作的列,如删除等等之类的。
                                                           {xtype:'actioncolumn',width:70,items:[{
         							icon: '../ext/selfimg/picture_delete.png',
         							tooltip:'删除封面',
         							handler:function(grid, rowIndex, colIndex){
         								var rec = store.getAt(rowIndex);
         								var id=rec.get("id");
         								 Ext.MessageBox.confirm("删除确认","确认是否删除?",function(btn){

							        	       }
							        	});
         							}
         						   }]}

type为:
actioncolumn


6.与Jquery成为一对好基友
有的时候,需要和jquery一起使用,只需引入jquery的适配器。
<script type="text/javascript" src="../ext/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../ext/ext-jquery-adapter.js"></script>
<script type="text/javascript" src="../ext/xheditor-1.1.9-zh-cn.min.js"></script>
<script type="text/javascript" src="../ext/ext-all.js"></script>
<script type="text/javascript" src="../ext/ext-lang-zh_CN.js"></script> 


如使用jquery的插件XKEditor编辑器。

{xtype:'textarea',fieldLabel:'正文',id:'news_details_proxy',name:'news_details_proxy',height:400,anchor: '-20'}

editor=$('#news_details_proxy').xheditor({html5Upload:false,upLinkUrl:fileUploadUrl,upLinkExt:"zip,rar,txt",upImgUrl:fileUploadUrl,upImgExt:"jpg,jpeg,gif,png",upFlashUrl:fileUploadUrl,upFlashExt:"swf",upMediaUrl:fileUploadUrl,upMediaExt:"avi"});	

发现总是无法成功,textarea还是老样子。
原来是因为在表单render动态的新增了组件,嗲用了doLayout,
                                          var renderNewsTypes=function(){
							Ext.Ajax.request({
								url : '<%=request.getContextPath()%>/mvc?MVC_BUS=NewsTypes&MVC_ACTION=list',
								success : function(resp, options) {
									var respText = Ext.util.JSON.decode(resp.responseText);
									var types=respText.list;
									typesInited=true;
									for(var i=0;i<types.length;i++){
										typesCheckBoxes.push({xtype:'checkbox',boxLabel:types[i].type_name,inputValue:types[i].id,name:'news_type_'+types[i].id,id:'news_type_'+types[i].id});
									}
									thiz.get(0).insert(1,{fieldLabel:'新闻类型',xtype:"checkboxgroup",columns: 4,items:typesCheckBoxes,name:'news_type_group',id:'news_type_group'});
									thiz.get(0).remove(thiz.get(0).findById("news_types_proxy"));
									thiz.doLayout();		
								},failure:function(){
									Ext.MessageBox.alert("警告","新闻内容拉取失败");
								}
							});
					}


所以必须在每次layout后,重新将编辑器渲染一下:
thiz.doLayout();
editor=$('#news_details_proxy').xheditor({html5Upload:false,upLinkUrl:fileUploadUrl,upLinkExt:"zip,rar,txt",upImgUrl:fileUploadUrl,upImgExt:"jpg,jpeg,gif,png",upFlashUrl:fileUploadUrl,upFlashExt:"swf",upMediaUrl:fileUploadUrl,upMediaExt:"avi"});									
								

7.一些不解
当文件AJAX上传的时候,服务器返回数据必须显示指定;
response.setContentType()"text/html";否则判断为失败。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值