在Ext里写大应用 (翻译:米米饭)
前言
我决定为那些使用ext2的用户写这篇文章,那些从html嵌入一些小脚本来生成窗口或表单的幼稚时代走过来的人,给那些给长长的代码,有无序结构作斗争的人.
一个问题 ,有多少人解决,就有多少种办法和方案,不一定按照我的方法来做才是最好的.只不过我真的想告诉你,以下这个方案是可行的,具有清晰结构,和易维护的,简单的说就是,It works!
什么是"大应用"
同时要在一个文件里用到ViewPort boardLayout,表格和表单,如果这还不算是大应用,如果每个表格又有十个窗口,表单,或者BoarderLayer,那这种呢?
在德语里有一个不错的单词 :Jein (也对也不对) 它是 是和不是的混合体
用它来说明上面的问题就是,应用什么时候算大?当他变大到你觉得大的时候就是大了.它意味着你开始面对一堆文件和问题.意味着你在一个文件里怎么也找不着你想要的那个,意味你不得不停下来理清不同组件之间的关系...
我们可以认为所有的应用都是大应用,即使是小应用这么写也可以获得合理的组织,当我们慢慢扩展它的新功能,新的代码,它会慢慢的变成真正的大应用.
所以最重要的是我们要认识到,我现在开始写大应用.!
文件和目录
这是我们首先要组织的东西,在Apache或其他服务器的目录里,我们总能看到一些目录,以下是我推荐的目录结构:
./css (可选连接)
./ext (连接)
./img (连接)
./js
index.html
连接的意思是指对应于实际文件的相对路径,好处是当你下载一个Ext新版本的时候,你只要修改一下它,而应用里无须修改一行就可以在新版本里运行,如果运行不正常的话,再改回去就行了.
css路径用于存放所有样式表单,如果你有全局的css或字体,你也可以建一个目录
ext 这个连接上面讲过了
img 这个连接到你的图片, 也可以包含一些图标的子目录
js 目录用于存放应用里创建的javascript文件
index.html 这个 html文件是应用的入口,你可以根据需要重命名, 同时也可能存在更多的入口文件,如登录的入口.
同时你可能还需要建立存放服务端代码的目录,如classes等,这根据你的应用的实际情况来定
index.html
最小的index.html的文件内容:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="./ext/resources/css/ext-all.css">
<link rel="stylesheet" type="text/css" href="./css/application.css">
<script type="text/javascript" src="./ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="./ext/ext-all-debug.js"></script>
<script type="text/javascript" src="./js/application.js"></script>
<title>A Big Application</title>
</head>
<body></body>
</html>
js/application.js
我们需要一个文件用于放onReady函数.我们称之为"应用js",最精简的应用js如下:
// vim: sw=4:ts=4:nu:nospell:fdc=4
/**
* An Application
*
* @author Ing. Jozef Sakáloš
* @copyright (c) 2008, by Ing. Jozef Sakáloš
* @date 2. April 2008
* @version $Id$
*
* @license application.js is licensed under the terms of the Open Source
* LGPL 3.0 license. Commercial use is permitted to the extent that the
* code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* License details: http://www.gnu.org/licenses/lgpl.html
*/
/*global Ext, Application */
Ext.BLANK_IMAGE_URL = './ext/resources/images/default/s.gif';
Ext.ns('Application');
// application main entry point
Ext.onReady(function() {
Ext.QuickTips.init();
// code here
}); // eo function onReady
// eof
这个文件的头和脚可能会不同,但是你要确信设置了Ext.BLANK_IMAGE_URL指向你的服务器.这个路径指向的是一个1x1的透明图片,用于指定Ext的图片位置,如果设置不正确,可能会引起一些渲染的问题,比如丢失图标等.
你需要为你的应用创建一个全局的对象变量.
你要确信 Ext.onReady是你的应用入口,从这个入口创建你的应用
css/application.css
你应该把你的css放入这个文件,如果你认为你的样式不多不需要单独创建文件,放入页面的head里的<style>标签中也是个不错的主意
事实正在相反,记住你在写一个大应用,每个文件都有自己的位置.如果你随手把它们乱放在head中,那将来你会碰上很多渲染的问题,而不知道到哪里去找到问题所在
错误的方法
刚入门的人往往怎么开始写Ext?
var vp = new Ext.Viewport({
layout:'border'
,items:[
new Ext.grid.GridPanel({
store:new Ext.data.Store({
proxy:new Ext.data.HttpProxy({ ...
等一下,这种方式写下去,我们很快会在application.js里写上10000行.显然这种方式是行不通的.
正确的方式 将之拆分
即使是最复杂的系统也包含一些相似的部件和元素,你要写的大应用也不例外,所以我们要开始分析它的部件,元素以有他们之间的关系.
先坐下,想一下,画个草图,列个表,你要弄清系统里的组成元素有哪里,起码要弄清最重要的那个.
预定义的类
现在你完成了应用的分析和确认了元素,可以开始下手写了,但是,如何下手? 最好的方式是继承ext组件,同时定义它的所有配置属性,或者你可以定义一个内置的配置对象,虽然很少用它来添加别的功能,但是它的好处是预定义,举例来说,我们要定义一个 "Personnel"的表格,它有一些指定的列,store ,排序项,编辑器,等
首先我们要定义一个这样的窗口
var win = new Ext.Window({
title:'Personnel'
,width:600
,height:400
,items:{xtype:'personnelgrid'}
});
win.show();
写一个预定义的类
[注意: 下面的结构可能在某些情况下不能运行]
以下是例子:
Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
Ext.apply(this, {
store:new Ext.data.Store({...})
,columns:[{...}, {...}]
,plugins:[...]
,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]
});
Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent
,onRender:function() {
this.store.load();
Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender
});
Ext.reg('personnelgrid', Application.PersonnelGrid);
我们在这里做了什么,我们的扩展了 Ext.grid.GridPanel,创建了一个新的扩展类 Application.PersonnelGrid,,然后我们把它注册成一个新的xtype,名为personnelgrid
我们根据personnel的需求给这个表格定义了所有的配置项,从这点来说,我们创建了一个新的组件.一个可以应用在所有需要用的地方的代码段,如在(window, border panel region, standalone)当中使用.我们还可以这样创建它:
var pg = new Application.PersonnelGrid();
或者使用xtype的方式(延迟实例化)
var win = new Ext.Window({
items:{xtype:'personnelgrid'}
,....
});
组织预定义类
上面的代码不需要也不应该在onReady里运行,因为它不对DOM做任何操作,它仅仅是创建一个javascript对象.所以它可以也应该被写在一个单位的js文件里,如js/Application.PersonnelGrid.js,同时它必须被包含在index.html的head中:
<script type="text/javascript" src="./js/Application.PersonnelGrid.js></script>
目前为止,一切OK,我们让所有的文件都有自己的地方.接下来,我们要做的就是开始写自己的预定义的类,将他们放在./js目录下,然后把它们包含在index.html里,使用它们的实例来建立我们的应用.就像组装一个玩具一样.
看起来不错吧.
下面还有更多的事等你做呢.
内部组件的通信
相像一下,我们需要一个这样的布局,在左边是连接列表,中间是标签页面.点击左边的连接即创建一个标签页,现在,我们应该把这样的逻辑放在什么地方.事件或创建程序呢,放在左边还是中间?
都不是!为什么?如果我们把创建和显示左边和中间页面的逻辑代码放在预定义的类中,那么如果没有center这个区域,它就会无效,我们什么tab也创建不了.
如果我们把它放在center的区域里,结果也是一样的,没有左边的区域,中间也无法存在.
我们只能把它放在包含west和center区域的布局容器中去,这也是唯一正确的放置内部组件通信代码的位置
接下来我们应该干什么.布局容器应该监听到west布局里的事件,应该为点击创建tabs.这里有一个这样的例子,在Saki的Ext例子 网站
生产系统
只要我们持续的编码代码,那么我们很快会在页面里包含越来越多的javascript文件,(像我差不多每天会增加差不多80个包含的js),这会使系统的性能下降.
最好的解决方法是把它们按顺序放在一个大的文件里,然后压缩.
在生产系统里我们应该包含这样几个js
ext-all.js
app-all.js and
application.js
关于如何压缩与混合代码,在另一个教程里讲.
结论
特定的ext类有特定的技术,还有更多服务端和客户端的技术需要我们去了解,不过以上就是一个总体的概念了.
编码愉快