Java学习

java,spring,structs,hibernate,jsf,ireport,jfreechart,jasperreport,tomcat,jboss -----本博客已经搬家了,新的地址是 http://www.javaly.cn 如果有对文章有任何疑问或者有任何不懂的地方,欢迎到www.javaly.cn (Java乐园)指出,我会尽力帮助解决。一起进步

 

EXT学习资料

EXT学习资料
EXT简介
无论你是Ext库的新手,抑或是想了解Ext的人,本篇文章的内容都适合你。本文将简单地介绍Ext的几个基本概念,和如何快速地做出一个动态的页面并运行起来,假设读者已具备了一些JavaScript经验和初级了解HTML Dom。
目錄
• 1 下载Ext
• 2 开始!
• 3 Element:Ext的核心
• 4 获取多个DOM的节点
• 5 响应事件
• 6 使用Widgets
o 6.1 MessageBox
o 6.2 Grid
o 6.3 还有更多的..
• 7 使用Ajax
o 7.1 PHP
o 7.2 ASP.Net
o 7.3 Cold Fusion

下载Ext
如果你未曾下载过,那应从这里下载最新版本的Ext http://extjs.com/downloads 。
针对你的下载需求,有几个不同的弹性选项。通常地,最稳定的版本,是较多人的选择。下载解包后,那个example文件夹便是一个探索Ext的好地方!
开始!
Download Example File
• IntroToExt.zip

我们将使用Ext,来完成一些JavaScript任务。
Zip文件包括三个文件:ExtStart.html, ExtStart.js和ExtStart.css。解包这三个文件到Ext的安装目录中(例如,Ext是在“C:"code"Ext"v1.0”中,那 应该在"v1.0"里面新建目录“tutorial”。双击ExtStart.htm,接着你的浏览器打开启动页面,应该会有一条消息告诉你配置已完毕。 如果是一个Javascript错误,请按照页面上的指引操作。
在你常用的IDE中或文本编辑器中,打开ExtStart.js看看:
Ext.onReady可能是你接触的第一个方法。这个方法是指当前DOM加载完毕后,保证页面内的所有元素能被Script引用(reference)。你可删除alert()那行,加入一些实际用途的代码试试:
Ext.onReady(function() {
alert("Congratulations!  You have Ext configured correctly!");
});
Element:Ext的核心
大多数的JavaScript操作都需要先获取页面上的某个元素(reference),好让你来做些实质性的事情。传统的JavaScript方法,是通过ID获取Dom节点的:
var myDiv = document.getElementById('myDiv');
这毫无问题,不过这样单单返回一个对象(DOM节点),用起来并不是太实用和方便。为了要用那节点干点事情,你还将要手工编写不少的代码;另外,对于不同类型浏览器之间的差异,要你处理起来可真头大了。
进入Ext.element 对象。元素(element)的的确确是Ext的心脏地带,--无论是访问元素(elements)还是完成一些其他动作,都要涉及它。Element的 API是整个Ext库的基础,如果你时间不多,只是想了解Ext中的一两个类的话,Element一定是首选!
由ID获取一个Ext Element如下(首页ExtStart.htm包含一个div,ID名字为“myDiv”,然后,在ExtStart.js中加入下列语句):
Ext.onReady(function() {var myDiv = Ext.get('myDiv');});
再回头看看Element对象,发现什么有趣的东东呢?
• Element包含了常见的DOM方法和属性,提供一个快捷的、统一的、跨浏览器的接口(若使用Element.dom的话,就可以直接访问底层DOM的节点。);
• Element.get()方法内置缓存处理(Cache),多次访问同一对象效率上有极大优势;
• 内置常用的DOM节点的动作,并且是跨浏览器的定位的位置、大小、动画、拖放等等(add/remove CSS classes, add/remove event handlers, positioning, sizing, animation, drag/drop)。
这意味着你可用少量的代码来做各种各样的事情,这里仅仅是一个简单的例子(完整的列表在ElementAPI中)。
继续在ExtStart.js中,在刚才我们获取好myDiv的位置中加入:
Java代码
  1. myDiv.highlight();      //黄色高亮显示然后渐退  
  2. myDiv.addClass('red');  // 添加自定义CSS类 (在ExtStart.css定义)  
  3. myDiv.center();         //在视图中将元素居中  
  4. myDiv.setOpacity(.25);  // 使元素半透明  

获取多个DOM的节点
通常情况下,想获取多个DOM的节点,难以依靠ID的方式来获取。有可能因为没设置ID,或者你不知道ID,又或者直接用ID方式引用有太多元素 了。这种情况下,你就会不用ID来作为获取元素的依据,可能会用属性(attribute)或CSS Classname代替。基于以上的原因,Ext引入了一个功能异常强大的Dom Selector库,叫做DomQuery。
DomQuery可作为单独的库使用,但常用于Ext,你可以在上下文环境中(Context)获取多个元素,然后通过Element接口调 用。令人欣喜的是,Element对象本身便有Element.selcect的方法来实现查询,即内部调用DomQuery选取元素。这个简单的例子 中, ExtStart.htm包含若干段落(
标签),没有一个是有ID的,而你想轻松地通过一次操作马上获取每一段,全体执行它们的动作,可以这样做:
// 每段高亮显示
Ext.select('p').highlight();
DomQuery的选取参数是一段较长的数组,其中包括W3C CSS3 Dom选取器、基本XPatch、HTML属性和更多,请参阅DomQuery API文档以了解这功能强大的库个中细节。
响应事件
到这范例为止,我们所写的代码都是放在onReady中,即当页面加载后总会立即执行,功能较单一——这样的话,你便知道,如何响应某个动作或事 件来执行你希望做的事情,做法是,先分配一个function,再定义一个event handler事件处理器来响应。我们由这个简单的范例开始,打开ExtStart.js,编辑下列的代码:
Java代码
  1. Ext.onReady(function() {  
  2.     Ext.get('myButton').on('click', function(){  
  3.         alert("You clicked the button");  
  4.     });  
  5. });  

加载好页面,代码依然会执行,不过区别是,包含alert()的function是已定义好的,但它不会立即地被执行,是分配到按钮的单击事件 中。用浅显的文字解释,就是:获取ID为'myDottom'元素的引用,监听任何发生这个元素上被单击的情况,并分配一个function,以准备任何 单击元素的情况。
正路来说,Element.select也能做同样的事情,即作用在获取一组元素上。下一例中,演示了页面中的某一段落被单击后,便有弹出窗口:
Java代码
  1. Ext.onReady(function() {  
  2.     Ext.select('p').on('click', function() {  
  3.         alert("You clicked a paragraph");  
  4.     });  
  5. });  

这两个例子中,事件处理的function均是简单几句,没有函数的名称,这种类型函数称为“匿名函数(anonymous function)”,即是没有名的的函数。你也可以分配一个有名字的event handler,这对于代码的重用或多个事件很有用。下一例等效于上一例:
Java代码
  1. Ext.onReady(function() {  
  2.     var paragraphClicked = function() {  
  3.         alert("You clicked a paragraph");  
  4.     }  
  5.     Ext.select('p').on('click', paragraphClicked);  
  6. });  

到目前为止,我们已经知道如何执行某个动作。但当事件触发时,我们如何得知这个event handler执行时是作用在哪一个特定的元素上呢?要明确这一点非常简单,Element.on方法传入到even handler的function中(我们这里先讨论第一个参数,不过你应该浏览API文档以了解even handler更多的细节)。在我们之前的例子中,function是忽略这些参数的,到这里可有少许的改变,——我们在功能上提供了更深层次的控制。必 须先说明的是,这实际上是Ext的事件对象(event object),一个跨浏览器和拥有更多控制的事件的对象。例如,可以用下列的语句,得到这个事件响应所在的DOM节点:
Java代码
  1. Ext.onReady(function() {  
  2.     var paragraphClicked = function(e) {  
  3.         Ext.get(e.target).highlight();  
  4.     }  
  5.     Ext.select('p').on('click', paragraphClicked);  
  6. });  

注意得到的e.target是DOM节点,所以我们首先将其转换成为EXT的Elemnet元素,然后执行欲完成的事件,这个例子中,我们看见段落是高亮显示的。
使用Widgets
(Widget原意为“小器件”,现指页面中UI控件)
除了我们已经讨论过的核心JavaScript库,当前的Ext亦包括了一系列的最前端的JavaScirptUI组件库。文本以一个常用的widget为例子,作简单的介绍。
MessageBox
比起略为沉闷的“HelloWolrd”消息窗口,我们做少许变化,前面我们写的代码是,单击某个段落便会高亮显示,现在是单击段落,在消息窗口中显示段落内容出来。
在上面的paragraphClicked的function中,将这行代码:
Ext.get(e.target).highlight();
替换为:
Java代码
  1. var paragraph = Ext.get(e.target);  
  2. paragraph.highlight();  
  3. Ext.MessageBox.show({  
  4.     title: 'Paragraph Clicked',  
  5.     msg: paragraph.dom.innerHTML,  
  6.     width:400,  
  7.     buttons: Ext.MessageBox.OK,  
  8.     animEl: paragraph  
  9. });  

这里有些新的概念需要讨论一下。在第一行中我们创建了一个局部变量(Local Variable)来保存某个元素的引用,即被单击的那个DOM节点(本例中,DOM节点指的是段落paragrah,事因我们已经定义该事件与< p>标签发生关联的了)。为什么要这样做呢?嗯...观察上面的代码,我们需要引用同一元素来高亮显示,在MessageBox中也是引用同一元素 作为参数使用。
一般来说,多次重复使用同一值(Value)或对象,是一个不好的方式,所以,作为一个具备良好OO思维的开发者,应该是将其分配到一个局部变量中,反复使用这变量!
现在,为了我们接下来阐述新概念的演示,请观察MessageBox的调用。乍一看,这像一连串的参数传入到方法中,但仔细看,这是一个非常特别 的语法。实际上,传入到MessageBox.show的只有一个参数:一个Object literal,包含一组属性和属性值。在Javascript中,Object Literal是动态的,你可在任何时候用{和}创建一个典型的对象(object)。其中的字符由一系列的name/value组成的属性,属性的格式 是[property name]:[property value]。在整个Ext中,你将会经常遇到这种语法,因此你应该马上消化并吸收这个知识点!
使用Object Literal的原因是什么呢?主要的原因是“可伸缩性(flexibility)”的考虑",随时可新增、删除属性,亦可不管顺序地插入。而方法不需要 改变。这也是多个参数的情况下,为最终开发者带来不少的方便(本例中的MessageBox.show())。例如,我们说这儿的foo.action方 法,有四个参数,而只有一个是你必须传入的。本例中,你想像中的代码可能会是这样的foo.action(null, null, null, 'hello').,若果那方法用Object Literal来写,却是这样, foo.action({ param4: 'hello' }),这更易用和易读。
Grid
Grid是Ext中人们最想先睹为快的和最为流行Widgets之一。好,让我们看看怎么轻松地创建一个Grid并运行。用下列代码替换ExtStart.js中全部语句:
Java代码
  1. Ext.onReady(function() {  
  2.     var myData = [  
  3.         ['Apple',29.89,0.24,0.81,'9/1 12:00am'],  
  4.         ['Ext',83.81,0.28,0.34,'9/12 12:00am'],  
  5.         ['Google',71.72,0.02,0.03,'10/1 12:00am'],  
  6.         ['Microsoft',52.55,0.01,0.02,'7/4 12:00am'],  
  7.         ['Yahoo!',29.01,0.42,1.47,'5/22 12:00am']  
  8.     ];  
  9.    
  10.     var ds = new Ext.data.Store({  
  11.         proxy: new Ext.data.MemoryProxy(myData),  
  12.         reader: new Ext.data.ArrayReader({id: 0}, [  
  13.             {name: 'company'},  
  14.             {name: 'price', type: 'float'},  
  15.             {name: 'change', type: 'float'},  
  16.             {name: 'pctChange', type: 'float'},  
  17.             {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}  
  18.     ])  
  19.     });  
  20.     ds.load();  
  21.    
  22.     var colModel = new Ext.grid.ColumnModel([  
  23.         {header: "Company", width: 120, sortable: true, dataIndex: 'company'},  
  24.         {header: "Price", width: 90, sortable: true, dataIndex: 'price'},  
  25.         {header: "Change", width: 90, sortable: true, dataIndex: 'change'},  
  26.         {header: "% Change", width: 90, sortable: true, dataIndex: 'pctChange'},  
  27.         {header: "Last Updated", width: 120, sortable: true,   
  28.         renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}  
  29.     ]);  
  30.    
  31.     var grid = new Ext.grid.Grid('grid-example', {ds: ds, cm: colModel});  
  32.         grid.render();  
  33.         grid.getSelectionModel().selectFirstRow();  
  34.     });  

这看上去很复杂,但实际上加起来,只有七行代码。第一行创建数组并作为数据源。实际案例中,你很可能从数据库、或者WebService那里得到 动态的数据。接着,我们创建并加载data store, data store将会告诉Ext的底层库接手处理和格式化这些数据。接着,我们定义一个column模型,用来轻松地调配Grid的每一列参数。最后我们生成这 个Grid,传入data store和column模型两个对象,进行渲染并选好第一行。不是太困难吧?如果一切顺利,完成之后你会看到像这样的:

当然,你可能未掌握这段代码的某些细节(像MemoryProxy究竟是什么?)但先不要紧,这个例子的目的是告诉你,用少量的代码,创建一个富 界面的多功能的UI组件而已——这是完全可能的,只要读者您有兴趣学习。这儿有许多学习Grid的资源。Ext Grid教程、交叉Gird演示和Grid API文档。
还有更多的..
这只是冰山一角。还有一打的UI Widgets可以供调用,如 layouts, tabs, menus, toolbars, dialogs, tree view等等。请参阅API文档中范例演示。
使用Ajax
在弄好一些页面后,你已经懂得在页面和脚本之间的交互原理(interact)。接下来,你应该掌握的是,怎样与远程服务器(remote server)交换数据,常见的是从数据库加载数据(load)或是保存数据(save)到数据库中。通过JavaScript异步无刷新交换数据的这种 方式,就是所谓的Ajax。Ext内建卓越的Ajax支持,例如,一个普遍的用户操作就是,异步发送一些东西到服务器,然后,UI元素根据回应 (Response)作出更新。这是一个包含text input的表单,一个div用于显示消息(注意,你可以在ExtStart.html中加入下列代码,但这必须要访问服务器):
<div id="msg" style="visibility: hidden"></div>

Name: <input type="text" id="name" /><br />

<input type="button" id="oKButton" value="OK" />
接着,我们加入这些处理交换数据的JavaScript代码到文件ExtStart.js中(用下面的代码覆盖):
Java代码
  1. Ext.onReady(function(){  
  2.     Ext.get('oKButton').on('click', function(){  
  3.         var msg = Ext.get('msg');  
  4.             msg.load({  
  5.             url: [server url], //换成你的URL  
  6.             params: 'name=' + Ext.get('name').dom.value,  
  7.             text: 'Updating...'  
  8.    
  9.         });  
  10.         msg.show();  
  11.     });  
  12. });  

这种模式看起来已经比较熟悉了吧!先获取按钮元素,加入单击事件的监听。在事件处理器中(event handler),我们使用一个负责处理Ajax请求、接受响应(Response)和更新另一个元素的Ext内建类,称作UpdateManager。 UpdateManager可以直接使用,或者和我们现在的做法一样,通过Element的load方法来引用(本例中该元素是id为“msg“的 div)。当使用Element.load方法,请求(request)会在加工处理后发送,等待服务器的响应(Response),来自动替换元素的 innerHTML。简单传入服务器url地址,加上字符串参数,便可以处理这个请求(本例中,参数值来自“name”元素的value),而text值 是请求发送时提示的文本,完毕后显示那个msg的div(因为开始时默认隐藏)。当然,和大多数Ext组件一样,UpdateManager有许多的参数 可选,不同的Ajax请求有不同的方案。而这里仅演示最简单的那种。
PHP
Java代码
  1. <? if(isset($_GET['name'])) {  
  2.     echo 'From Server: '.$_GET['name'];  
  3. }  
  4. ?>  
  5. ASP.Net  
  6. protected void Page_Load(object sender, EventArgs e)  
  7. {  
  8.     if (Request["name"] != null)  
  9.        {  
  10.         Response.Write("From Server: " + Request["name"]);  
  11.         Response.End();  
  12.     }  
  13. }  
  14. Cold Fusion   
  15. <cfif StructKeyExists(url, "name")>  
  16.     <cfoutput>From Server: #url.name#</cfoutput>  
  17. </cfif>  

最后一个关于Ajax隐晦的地方就是,服务器实际处理请求和返回(Resposne)是具体过程。这个过程会是一个服务端页面,一个 Servlet,一个 Http调度过程,一个WebService,甚至是Perl或CGI脚本,即不指定一个服务器都可以处理的http请求。让人无法预料的是,服务器返回 什么是服务器的事情,无法给一个标准的例子来覆盖阐述所有的可能性。(这段代码输出刚才我们传入'name'的那个值到客户端,即发送什么,返回什么)。
使用Ajax的真正挑战,是需要进行适当的手工编码,并相应格式化为服务端可用接受的数据结构。有几种格式供人们选择(最常用为 JSON/XML)。正因 Ext是一种与服务器语言免依赖的机制,使得其它特定语言的库亦可用于Ext处理Ajax服务。只要页面接受到结果是EXT能处理的数据格式,Ext绝不 会干涉服务器其他的事情!要全面讨论这个问题,已超出本文的范围。推荐正在Ajax环境下开发的您,继续深入阅读Ext Ajax教程。

下一步是?
现在你已经一睹Ext其芳容,知道她大概能做些什么了。下面的资源有助您进一步深入了解:
EXT源码概述
揭示源代码
Javascript是一门解释型的语言,意味着在运行之前代码是没有经过编译的。按照这种理论,在你网站上所发播的Ext代码是我们看的懂的 (human-readible)。我这里说“理论上”,是因为实际情况中,很多源代码是经过某些自动化步骤的处理,生成很小几行的文件最终发布的,通过 剔除空白符号和注释,或混淆等的方法,以减小文件大小。
仔细看看EXT标准源码ext-core.js,你会发现这是一段超长的源码。这是刚才提及的自动化步骤生成的结果--对浏览器来说不错!可是对于我们是难以阅读的。
ext-core.js
Java代码
  1. /* 
  2.  * Ext JS Library 1.1 
  3.  * Copyright(c) 2006-2007, Ext JS, LLC. 
  4.  * licensing@extjs.com 
  5.  *  
  6.  * http://www.extjs.com/license 
  7.  */  
  8.    
  9. Ext.DomHelper=function(){var _1=null;var _2=/^(?:br|frame...  
  10.    
  11. Ext.Template=function(_1){if(_1 instanceof Array){_1...  

...
接着看下去的是ext-core-debug.js (注意在文件名后面加上-debug的JS文件), 我会发现是全部已格式化好的源代码。这个文件是配合调时器所使用的,像Firebug的工具能够可以让你一步一步地、一行一行地调试代码。你也会发现文件 的体积将近大了一倍之多,这便是没有压缩或混淆的缘故。
ext-core-debug.js
Java代码
  1. /* 
  2.  * Ext JS Library 1.1 
  3.  * Copyright(c) 2006-2007, Ext JS, LLC. 
  4.  * licensing@extjs.com 
  5.  *  
  6.  * http://www.extjs.com/license 
  7.  */  
  8.    
  9. Ext.DomHelper = function(){  
  10.     var tempTableEl = null;  
  11.     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;  
  12.     var tableRe = /^table|tbody|tr|td$/i;  

...
该调试版本可以在调试阶段方便地检查EXT库运行到哪一步,但是你还是会错过一个有价值的...代码注释!要完整地看到代码,就要阅读真正的原始代码!
发布Ext源码时的一些细节
你在download得到的压缩文档,包含在这些文件夹之中的,有一source的子目录。在这个文件夹里面,正如所料,是全部的EXT的源文件,遵从Lesser GNU (LGPL) 开源的协议。对于EXT开发者来说应该非常适合。
用你日常使用文本编辑器打开源代码的任意一个文件(推荐有高亮显示的编辑器,或是在这里full-featured IDE看看),便可以开始我们的探险!
我应该从哪里开始?
Ext代码库里面包含了许多各种各样的文件,甚至令人觉得有点望而生畏。好在,Ext是一个通过充分考虑后而设计的JavaScript库,-- 在底层的代码为各项应用提供稳健的基础如跨浏览器的各种DOM操控,使得在上层的类classes运行于一个较高级的抽象层面(class 一术语与我们已习惯的Java和C++语言稍微有所不同,但一些概念如继承则可是如此类推去理解的--有关面向对象的JavaScript的更多资料,请 参见Introduction to object-oriented (OO) JavaScript)。
这意味着,当浏览源码的时候,采取“自顶向下(bottom-up)”还是“自下向顶(top-down)”的方式,都是无关紧要的。你所熟 悉API里面的代码已经是属于最高的抽象层面的范畴,你可以根据你的兴趣,顺着这些你熟悉的API逐步深入。但是你若赞同我的看法,并打算深入了解其个中 原理,最理想的地方是从底层代码开始。
适配器Adapters
浏览器读取第一个源文件,当中的一个任务就是创建Ext对象本身。 Ext.js
Ext = {};
Ext成型于YahooUI的Javascript库的扩展。在当时,Ext须依赖YUI的底层代码来处理跨浏览器的问题。现在ExtJS已经是 独立、免依赖的库了(standalone ),你可将YUI替换为另外你所选择javascript库,如prototype、jQuery、或者是这些之中的最佳选择,-Ext自带的底层库。负 责将这些库(包括Ext自带的底层库)映射为Ext底层库的这部分代码,我们称之为适配器(Adapters)。这部分源码位于 source/adapter的子目录。当项目引入Ext的时候便需要选择好你准备使用的适配器。
核心Core
source/core中的文件是构建于适配器API之上的“相对”最底层的源码。有些的源码甚至“底层”到直接为独立库的代码直接使用。这意味 着应先了解和学习这整个库,再学习剩余的部分也不迟。要了解Ext的各种“Magic”和核心层面,就应该把重点放在source/core 目录下的各个源代码。

Javascript中的作用域(scope)
事前准备
学习本教程的最佳方法是随手准备好Firefox中的工具Firebug。这样使得您可以即刻测试教程的例子。
如果机子上还没有FireFox和FireBug,就应该尽快安装一套来用。
定义
作用域scope
1.(名词)某样事物执行、操作、拥有控制权的那么一个区域 [1]
2. (名词) 编写程序时,程序之中变量的可见度;例如,一个函数能否使用另外一个函数所创建的变量。[2]
可是这能够说明什么问题呢? 每当有人在说“这是作用域的问题”或“作用域搞错了”的时候,那就是说某个函数运行起来的时候,找不到正确变量的位置。这样我们便知道应该从哪一方面入手,查找出问题所在。
正式开始
实际上每一个你定义的函数都是某个对象的方法。甚至是这样的写法:
function fn() {
    alert(11);
}
老兄你不是故弄玄虚吧~。做一个这样的演示可真得是简单得要命。没错!本例不需要任何Javascript文件,服务器或html。你只要打开 firefox,弹出firebug,点击console tab。在Firefox状态栏上面看到有>>>提示的地方就可以输入了。
输入:
function fn() { alert(11); };
然后回车。一切安然...你刚才做的实际上是定义了一个函数fn。接着试试:
fn();
然后回车。得到11的警告窗口?还不错吧?接着试试:
window.fn();
this.fn();
得到一样的结果吧?这是因为函数fn是window对象的一个方法,在第二行的"this"的作用域实际指向了windows对象。不过多数情况中你不需要像这样window.myFunction(...)地调用函数,这样太麻烦了,程序员工作起来会很不方便。
window对象
window 对象总是存在的,你可理解其为一个浏览器窗口对象。它包含了其它所有的对象如document 和所有的全局变量。
你可以打开Firebug,切换到 Script 页面并在Firebug右侧的New watch expression... 里面输入 window。观察window对象究竟有什么在里面。
接着,尝试找出我们之前定义过的fn函数。
另外,每个frame或iframe拥有其自身的window对象,其自身的全局空间。
理解作用域
接下的内容开始有点复杂了。切换到Firebug Console标签页然后输入:
var o1 = {testvar:22, fun:function() { alert('o1: ' + this.testvar); }};
var o2 = {testvar:33, fun:function() { alert('o2: ' + this.testvar); }};
结果是什么?你声明了o1 和 o2两个对象,分别都有一些属性和方法,但值不同。

接着试试:
fun();
window.fun();
this.fun();
出错了,是吧?因为window对象(等价于this)并没有fun的方法。试一试下面的:
o1.fun();
o2.fun();
22和33出来了?非常好!
接下来这部分的内容最复杂啦。基于这个原始的函数,如果对象的数量多的话,你必须为每个对象加上这个函数-明显是重复劳动了。这样说 吧,o1.fun写得非常清晰的而且为了搞掂它已经占用了我一个星期的开发时间。想象一下代码到处散布着this变量,怎么能不头疼?如果要将调用(执 行)的o1.fun方法但this会执行o2,应该怎么实现呢?试一试下面的:
o1.fun.call(o2);
明白了吗?当执行o1的fun方法时你强行将变量this指向到o2这个对象,换句话说,更加严谨地说:o1.fun的方法在对象o2的作用域下运行。
当运行一个函数,一个对象的方法时,你可将作用域当作this值的变量。
变量的可见度
变量的可见度和作用域的关系非常密切。我们已经了解到,可在任何对象的外部,声明变量,或在全局的函数(函数也是变量的一种)也可以,更严格说, 它们是全局对象window的属性。 全局变量在任何地方都可见;无论函数的内部还是外部。如果你在某一个函数内修改了一个全局变量,其它函数也会得知这个值是修改过的。
对象可以有它自己的属性(像上面的testvar),这些属性允许从内部或是外部均是可见的。试:
alert(o1.testvar); // 从外部访问o1的属性testvar
从内部访问的演示可在两个测试对象的fun方法找到。
用关键字var在内部声明,相当于声明局部变量(局部声明也是在一条链上,即Scope Chain 作用域链上,Frank注):
Java代码
  1. i = 44;   
  2. function fn2() {   
  3.     var i = 55;   
  4.     alert(i);   
  5. }  
  6. fn2();  

将得到什么?对了,55。声明在函数fn2的变量i是一个本地变量(局部变量),和等于44的全局变量i 44没什么关系。 But:
alert(i);
这会访问全局变量i,显示44。
希望本文能帮助读者彻底理解作用域变量可见性的含义。
EXT程序规划入门
事前准备
本教程假设你已经安装好ExtJS库。安装的目录是extjs 并位于你程序的上一级目录。如果安装在其它地方你必须更改路径,更改示例文件中script标签的src的属性。
需要些什么?
除ExtJS库本身外,我们还需要两个文件:
• applayout.html
• applayout.js

先看看一份html文档,比较精简。并附有详细说明:
applayout.html
Java代码
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   
  2.     "http://www.w3.org/TR/html4/loose.dtd">  
  3. <html>  
  4. <head>  
  5.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  6.     <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">  
  7.     <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>  
  8.     <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>  
  9.     <script type="text/javascript" src="applayout.js"></script>  
  10.     <!-- 本地化的脚本引用在这里 -->  
  11.     <script type="text/javascript">  
  12.         Ext.onReady(myNameSpace.app.init, myNameSpace.app);  
  13.     </script>  
  14.     <title>Application Layout Tutorial</title>  
  15. </head>  
  16. <body>  
  17. </body>  
  18. </html>  

开头的两行声明了文档的类型。程序可以不用doctype,但是这样的话浏览器可能默认其为Quirks怪僻类型,会导致处理跨浏览器这一问题上出现差异。

我们采用HTML 4.01 Transitional的文档类型,该类型在主流浏览器上支持得不错。当然,你也可以根据你的需求采用其它类型的doctype,但是记住别忘了要加上doctype。
接着指定HTML头部的Content-Type。做这些事情其实很琐碎,但总是有益处。
然后引入EXT的样式,适配器和EXTJS本身。有两种版本的ExtJS:
• ext-all.js - 不能直接阅读,加载时更快,用于产品发布
• ext-all-debug.js - 便于阅读,开发阶段使用,
开发阶段的时候便需要引入debug的版本。

applayout.js这个文件就是我们的程序,紧跟着的是本地化的脚本,这里可以换成Extjs翻译好的版本
跟着我们开始分配事件句柄(event handler),使得在文档全部加载完毕后,程序就可以初始化(运行)。
下面的这一行:
Ext.onReady(myNameSpace.app.init, myNameSpace.app);
可这样说:当文档全部加载完毕,就运行myNameSpace.app的init方法,规定的作用域是myNameSpace.app。
然后是标题,头部的结尾,body(当前空)和结束标签。
文档的解说就说到这儿了。
applayout.js
Java代码
  1. /** 
  2.   * Application Layout 
  3.   * by Jozef Sakalos, aka Saki 
  4.   * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners_(Chinese) 
  5.   */  
  6.    
  7. // 填充图片的本地引用  
  8. Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';  
  9.    
  10. // 创建命名空间  
  11. Ext.namespace('myNameSpace');  
  12.    
  13. // 创建应用程序  
  14. myNameSpace.app = function() {  
  15.     // 元素还没创建,未能访问  
  16.    
  17.     // 私有变量  
  18.    
  19.     // 私有函数  
  20.    
  21.     // 公共空间  
  22.     return {  
  23.         // 公共的属性,如,要转换的字符串  
  24.         // 公共方法  
  25.         init: function() {  
  26.             alert('应用程序初始化成功。');  
  27.         }  
  28.     };  
  29. }(); // 程序底部  
  30.    

// 文件底部
文件最开始的几行是注释,说明该文件的主要内容,作者,作者相关的资讯。没有任何注释的程序也可以正常的运行,-但请记住:每次写的程序要容易给 人看得懂的 Always write your application as if you would write it for another.当你回头看你几个月前写的代码,发现你根本不记得自己写过什么的时候,就会明白这个道理,并养成编码的好习惯。接着是要指向你服务器的填 充图片,如不指定则默认extjs.com。每次运行程序的时候都访问extjs.com,不推荐这样,应该先修改这个常量值指向到本地。

现在自定义命名空间。将所有变量和方法都划分到一个全局对象下管理,这样的好处是避免了变量名冲突和由不同函数干扰了全局变量的值。名字(namespace)可按自己的方案选择。

整段代码的重点是,我们创建了 myNameSpace对象的属性app,其值是一个函数立刻运行之后的返回值。
如果运行我们的代码:
var o = function() {
    return {p1:11, p2:22};
}();
实际上我们创建了一个匿名函数(没有名字的函数),经过解释(预编译?)之后让它立刻运行(注意函数后面的())。最后将函数返回的对象(注意此时是一个object变量)分配到变量o。我们的程序便是这种思路去写的。
你可以把私有变量和私有函数直接定义在function和return这两个声明之间,但是请切记:此时不能访问任何html页面中的元素,那会导致错误,因为这段代码在加载时页面的head中就运行了,而这时候html页面中的其它元素还没有被加载进来。
另外一方面,函数init,是由匿名函数返回的对象的一个方法而已。它会在文档全部加载后才运行。换言之整个DOM树已经是可用的了。
一切都还好吧~如果能正确运行http://yourserver.com/applayout/applayout.html,不出现什么错误的话将出现一个警告。
接下来是利用这个空白的模板,讨论本文的重点。
公开Public、私有Private、特权的Privileged?
让我们加入一些有趣内容到程序中去吧。在页面applayout.html的body标签中加入:
<div id="btn1-ct"></div>
空白的div会当作按钮的容器来使用。然后在applayout.js加入下来代码:
Java代码
  1. /** 
  2.   * Application Layout 
  3.   * by Jozef Sakalos, aka Saki 
  4.   * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners_(Chinese) 
  5.   */  
  6.    
  7. //  填充图片的本地引用  
  8. Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';  
  9.    
  10. // 创建命名空间  
  11. Ext.namespace('myNameSpace');  
  12.    
  13. // 创建应用程序  
  14. myNameSpace.app = function() {  
  15.     // 元素还没创建,未能访问  
  16.    
  17.     // 私有变量  
  18.     var btn1;  
  19.     var privVar1 = 11;  
  20.    
  21.     // 私有函数  
  22.     var btn1Handler = function(button, event) {  
  23.         alert('privVar1=' + privVar1);  
  24.         alert('this.btn1Text=' + this.btn1Text);  
  25.     };  
  26.    
  27.     // 公共空间  
  28.     return {  
  29.         // 公共的属性,如,要转译的字符串  
  30.         btn1Text: 'Button 1'  
  31.    
  32.         // 公共方法  
  33.         , init: function() {  
  34.             btn1 = new Ext.Button('btn1-ct', {  
  35.                   text: this.btn1Text  
  36.                 , handler: btn1Handler  
  37.             });  
  38.         }  
  39.     };  
  40. }(); //程序底部  

// 文件底部
变量btn1 和privVar1 是私有的。 那意味着在程序外部他们是不能够被访问的,而且也不可见。私有函数btn1Handler也是同样道理。
另外一个方面,btn1Text是公共变量所以可以被程序外部访问或者是修改(我们稍后将会演示)。
函数init是特权的,即是私有变量和公共变量两者都可以被它访问到。在本例中,公共变量this.btn1Text和私有函数btn1Handler都能够被特权函数init所访问。同时,相对外界来说,它也属于公共成员的一种。
Ok,运行看看。能看到左上角的按钮吗?很好,点击它。得到一个privVar1=11的警告。这说明私有函数能访问私有变量。
但是在第二个警告中遇到了this.btn1Text=undefined的问题,这好像不应该这样。个中原因是因为位于事件句柄(event handler)中的变量this没有正确指向到我们的程序。你需要用scope:this 指明这个作用域(这里的this关键字所指示的scope应该是btn1变量):
Java代码
  1. btn1 = new Ext.Button('btn1-ct', {  
  2.       text: this.btn1Text  
  3.     , handler: btn1Handler  
  4.     , scope: this  
  5. });  

刷新一下,可以了吧?
重写公共变量
在applayout.js底部加入下列代码:
Ext.apply(myNameSpace.app, {
    btn1Text:'Taste 1'
});

// 文件底部
这代码是用来干什么的呢?首先它创建了我们的程序对象然后改变(重写)公共变量btn1Text的值。运行后将看到按钮上文字的变化。

把文本都放到公共变量,以便于以后的国际化翻译工作,而不需要修改程序的内部代码。
当然你也可以将其它的值例如尺寸、样式、等等的总之是可自定义的选项都放到公共变量中。免于在数千行代码之中为查找某个颜色而费劲。
重写(Overriding)公共函数
接着更改一下代码,让它读起来是这样的:
Java代码
  1. Ext.apply(myNameSpace.app, {  
  2.       btn1Text:'Taste 1'  
  3.     , init: function() {  
  4.         try {  
  5.             btn1 = new Ext.Button('btn1-ct', {  
  6.                   text: this.btn1Text  
  7.                 , handler: btn1Handler  
  8.                 , scope: this  
  9.             });  
  10.         }  
  11.         catch(e) {  
  12.             alert('错误: "' + e.message + '" 发生在行: ' + e.lineNumber);  
  13.         }  
  14.     }  
  15. });  


// end of file
我们这里将init重写了一篇,主要是在原来代码的基础上加入异常控制,以便能够捕获异常。试运行一下看还有没有其它的变化?
嗯 是的,出现了btn1Handler 未定义的错误。这是因为新的函数虽然尝试访问私有变量但它实际是不允许的。正如所见,原init是特权函数可访问私有空间,但新的init却不能。之所以 不能访问私有空间,是因为:禁止外部代码No code from outside,哪怕是尝试重写特权方法。
DomQuery基础
本教程旨在为读者了解怎样利用单例对象Ext.DomQuery,浏览穿梭于DOM树之中和获取对象,提供一个起点。
DomQuery基础
DomQuery的select函数有两个参数。第一个是选择符字符(selector string )而第二个是欲生成查询的标签ID(TAG ID)。
本文中我准备使用函数“Ext.query”但读者须谨记它是“Ext.DomQuery.select()”的简写方式。
这是要入手的html:
Java代码
  1. <html>  
  2.  <head>  
  3.   <script type="text/javascript" src="../js/firebug/firebug.js"></script>  
  4.  </head>  
  5.  <body>  
  6.   <script type="text/javascript" src="../ext/ext-base.js"></script>  
  7.   <script type="text/javascript" src="../ext/ext-core.js"></script>  
  8.   <div id="bar"  class="foo">  
  9.    I'm a div ==> my id: bar, my class: foo  
  10.    <span class="bar">I'm a span within the div with a foo class</span>  
  11.    <a href="http://www.extjs.com" target="_blank">An ExtJs link</a>  
  12.   </div>  
  13.   <div id="foo" class="bar">  
  14.    my id: foo, my class: bar  
  15.    <p>I'm a P tag within the foo div</p>  
  16.    <span class="bar">I'm a span within the div with a bar class</span>  
  17.    <a href="#">An internal link</a>  
  18.   </div>  
  19.  </body>  
  20. </html>  

第一部分:元素选择符Selector
假设我想获取文档内所有的“span”标签:
Java代码
  1. // 这个查询会返回有两个元素的数组因为查询选中对整个文档的所有span标签。  
  2. Ext.query("span");   
  3. // 这个查询会返回有一个元素的数组因为查询顾及到了foo这个id。  
  4. Ext.query("span", "foo");  
  5. 注意刚才怎么传入一个普通的字符串作为第一个参数。   
  6. 按id获取标签,你需要加上“#”的前缀:   
  7. // 这个查询会返回包含我们foo div一个元素的数组!  
  8. Ext.query("#foo");  
  9. 按class name获取标签,你需要加上“.”的前缀:   
  10. /*这个查询会返回有一个元素的数组, 
  11. 包含与之前例子一样的div但是我们使用了class name来获取*/  
  12. Ext.query(".foo");  
  13. 你也可以使用关键字“*”来获取所有的元素:   
  14. // 这会返回一个数组,包含文档的所有元素。  
  15. Ext.query("*");  
  16. 要获取子标签,我们只须在两个选择符之间插入一个空格:   
  17. // 这会返回有一个元素的数组,包含p标签的div标签   
  18. Ext.query("div p");  
  19. // 这会返回有两个元素的数组,包含span标签的div标签   
  20. Ext.query("div span");  
  21.   
  22. 还有三个的元素选择符,待后续的教程会叙述。 ""   
  23. 如果朋友你觉得这里说得太简单的话,你可以选择到DomQuery 文档看看,可能会有不少收获:)   
  24. 第二部分:属性选择符Attributes selectors   
  25. 这些选择符可让你得到基于一些属性值的元素。属性指的是html元素中的href, id 或 class。   
  26. // 我们检查出任何存在有class属性的元素。  
  27. // 这个查询会返回5个元素的数组。  
  28. Ext.query("*[class]"); // 结果: [body#ext-gen2.ext-gecko, div#bar.foo, span.bar, div#foo.bar, span.bar]  
  29. 现在我们针对特定的class属性进行搜索。   
  30. // 这会得到class等于“bar”的所有元素  
  31. Ext.query("*[class=bar]");  
  32.    
  33. // 这会得到class不等于“bar”的所有元素  
  34. Ext.query("*[class!=bar]");  
  35.    
  36. // 这会得到class从“b”字头开始的所有元素  
  37. Ext.query("*[class^=b]");  
  38.    
  39. //这会得到class由“r”结尾的所有元素  
  40. Ext.query("*[class$=r]");  
  41.    
  42. //这会得到在class中抽出“a”字符的所有元素  
  43. Ext.query("*[class*=a]");  
  44. 第三部分: CSS值元素选择符  
  45. 这些选择符会匹配DOM元素的style属性。尝试在那份html中加上一些颜色:   
  46. <html>  
  47.  <head>  
  48.   <script type="text/javascript" src="../js/firebug/firebug.js"></script>  
  49.  </head>  
  50.  <body>  
  51.   <script type="text/javascript" src="../ext/ext-base.js"></script>  
  52.   <script type="text/javascript" src="../ext/ext-core.js"></script>  
  53.   <div id="bar" class="foo" style="color:red;">  
  54.    我是一个div ==> 我的id是: bar, 我的class: foo  
  55.    <span class="bar" style="color:pink;">I'm a span within the div with a foo class</span>  
  56.    <a href="http://www.extjs.com" target="_blank" style="color:yellow;">An ExtJs link with a blank target!</a>  
  57.   </div>  
  58.   <div id="foo" class="bar" style="color:fushia;">  
  59.    my id: foo, my class: bar  
  60.    <p>I'm a P tag within the foo div</p>  
  61.    <span class="bar" style="color:brown;">I'm a span within the div with a bar class</span>  
  62.    <a href="#" style="color:green;">An internal link</a>  
  63.   </div>  
  64.  </body>  
  65. </html>  
  66. 基于这个CSS的颜色值我们不会作任何查询,但可以是其它的内容。它的格式规定是这样的:   
  67. 元素{属性 操作符 值}   
  68. 注意我在这里是怎么插入一个不同的括号。   
  69. 所以,操作符(operators)和属性选择符(attribute selectors)是一样的。   
  70. // 获取所以红色的元素  
  71. Ext.query("*{color=red}"); // [div#bar.foo]  
  72.    
  73. // 获取所有粉红颜色的并且是有红色子元素的元素  
  74. Ext.query("*{color=red} *{color=pink}"); // [span.bar]  
  75.    
  76. // 获取所有不是红色文字的元素  
  77. Ext.query("*{color!=red}");    
  78. //[html, head, script firebug.js, link, body#ext-gen2.ext-gecko,  
  79. // script ext-base.js, script ext-core.js, span.bar,   
  80. //a www.extjs.com, div#foo.bar, p, span.bar, a test.html#]  
  81.    
  82. // 获取所有颜色属性是从“yel”开始的元素  
  83. Ext.query("*{color^=yel}"); // [a www.extjs.com]  
  84.    
  85. // 获取所有颜色属性是以“ow”结束的元素  
  86. Ext.query("*{color$=ow}"); // [a www.extjs.com]  
  87.    
  88. // 获取所有颜色属性包含“ow”字符的元素  
  89. Ext.query("*{color*=ow}"); // [a www.extjs.com, span.bar]  
  90.   
  91. 第四部分:伪类选择符Pseudo Classes selectors   
  92. 仍然是刚才的网页,但是有所不同的只是新加上了一个UL元素、一个TABLE元素和一个FORM元素,以便我们可以使用不同的伪类选择符,来获取节点。   
  93. <html>  
  94.  <head>  
  95.   <script type="text/javascript" src="../js/firebug/firebug.js"></script>  
  96.  </head>  
  97.  <body>  
  98.   <script type="text/javascript" src="../ext/ext-base.js"></script>  
  99.   <script type="text/javascript" src="../ext/ext-core.js"></script>  
  100.   <div id="bar" class="foo" style="color:red; border: 2px dotted red; margin:5px; padding:5px;">  
  101.    I'm a div ==> my id: bar, my class: foo  
  102.    <span class="bar" style="color:pink;">I'm a span within the div with a foo class</span>  
  103.    <a href="http://www.extjs.com" target="_blank" style="color:yellow;">An ExtJs link with a blank target!</a>  
  104.   </div>  
  105.   <div id="foo" class="bar" style="color:fushia; border: 2px dotted black; margin:5px; padding:5px;">  
  106.    my id: foo, my class: bar  
  107.    <p>I'm a P tag within the foo div</p>  
  108.    <span class="bar" style="color:brown;">I'm a span within the div with a bar class</span>  
  109.    <a href="#" style="color:green;">An internal link</a>  
  110.   </div>  
  111.   <div style="border:2px dotted pink; margin:5px; padding:5px;">  
  112.    <ul>  
  113.     <li>Some choice #1</li>  
  114.     <li>Some choice #2</li>  
  115.     <li>Some choice #3</li>  
  116.     <li>Some choice #4 with a <a href="#">link</a></li>  
  117.    </ul>  
  118.    <table style="border:1px dotted black;">  
  119.     <tr style="color:pink">  
  120.      <td>1st row, 1st column</td>  
  121.      <td>1st row, 2nd column</td>  
  122.     </tr>  
  123.     <tr style="color:brown">  
  124.         <td colspan="2">2nd row, colspanned! </td>  
  125.     </tr>  
  126.     <tr>  
  127.      <td>3rd row, 1st column</td>  
  128.      <td>3rd row, 2nd column</td>  
  129.     </tr>   
  130.    </table>  
  131.   </div>  
  132.   <div style="border:2px dotted red; margin:5px; padding:5px;">  
  133.    <form>  
  134.     <input id="chked" type="checkbox" checked/><label for="chked">I'm checked</label>  
  135.     <br /><br />  
  136.     <input id="notChked" type="checkbox" /><label for="notChked">not me brotha!</label>  
  137.    </form>  
  138.   </div>  
  139.  </body>  
  140. </html>  
  141.    
  142. 接着:  
  143. /* 
  144.  this one gives us the first SPAN child of its parent 
  145. */  
  146. Ext.query("span:first-child"); // [span.bar]  
  147.    
  148. /* 
  149.  this one gives us the last A child of its parent 
  150. */  
  151. Ext.query("a:last-child") // [a www.extjs.com, a test.html#]  
  152.    
  153. /* 
  154.  this one gives us the second SPAN child of its parent 
  155. */  
  156. Ext.query("span:nth-child(2)") // [span.bar]  
  157.    
  158. /* 
  159.  this one gives us ODD TR of its parents 
  160. */  
  161. Ext.query("tr:nth-child(odd)") // [tr, tr]  
  162.    
  163. /* 
  164.  this one gives us even LI of its parents 
  165. */  
  166. Ext.query("li:nth-child(even)") // [li, li]  
  167.    
  168. /* 
  169.  this one gives us A that are the only child of its parents 
  170. */  
  171.    
  172. Ext.query("a:only-child") // [a test.html#]  
  173.    
  174. /* 
  175.  this one gives us the checked INPUT 
  176. */  
  177. Ext.query("input:checked") // [input#chked on]  
  178.    
  179. /* 
  180.  this one gives us the first TR 
  181. */  
  182. Ext.query("tr:first") // [tr]  
  183.    
  184. /* 
  185.  this one gives us the last INPUT 
  186. */  
  187. Ext.query("input:last") // [input#notChked on]  
  188.    
  189. /* 
  190.  this one gives us the 2nd TD 
  191. */  
  192. Ext.query("td:nth(2)") // [td]  
  193.    
  194. /* 
  195.  this one gives us every DIV that has the "within" string 
  196. */  
  197. Ext.query("div:contains(within)") // [div#bar.foo, div#foo.bar]  
  198.    
  199. /* 
  200.  this one gives us every DIV that doesn't have a FORM child 
  201. */  
  202. Ext.query("div:not(form)") [div#bar.foo, div#foo.bar, div]  
  203.    
  204. /* 
  205.  This one gives use every DIV that has an A child 
  206. */  
  207. Ext.query("div:has(a)") // [div#bar.foo, div#foo.bar, div]  
  208.    
  209. /*  
  210.  this one gives us every TD that is followed by another TD.  
  211.  obviously, the one that has a colspan property is ignored. 
  212. */  
  213. Ext.query("td:next(td)") // [td, td]  
  214.    
  215. /* 
  216.  this one gives us every LABEL that is preceded by an INPUT 
  217. */  
  218. Ext.query("label:prev(input)") //[label, label]  

扩展EXT组件
要创建的扩展是一个在文字前面能够显示图标的这么一个Ext.form.Combobox。将其中一个功能举例来说,就是要在一块选择里,国家名称连同国旗一并出现。
我们先给扩展起个名字,就叫Ext.ux.IconCombo。
文件的创建
首要的步骤是准备好开发中将会使用的文件。需下列文件:
• iconcombo.html: 新扩展将会使用的 html markup
• iconcombo.js: 程序javascript代码
• Ext.ux.IconCombo.js: 扩展的javascript文件
• Ext.ux.IconCombo.css: 扩展样式表
Java代码
  1. iconcombo.html  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   
  3.     "http://www.w3.org/TR/html4/loose.dtd">  
  4. <html>  
  5. <head>  
  6.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  7.     <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">  
  8.     <link rel="stylesheet" type="text/css" href="Ext.ux.IconCombo.css">  
  9.     <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>  
  10.     <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>  
  11.     <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>  
  12.     <script type="text/javascript" src="iconcombo.js"></script>  
  13.     <!-- A Localization Script File comes here -->  
  14.     <script type="text/javascript">Ext.onReady(iconcombo.init, iconcombo);</script>  
  15.     <title>Ext.ux.IconCombo Tutorial</title>  
  16. </head>  
  17. <body>  
  18. <div style="position:relative;width:300px;top:24px;left:64px;font-size:11px">  
  19.     <div>Icon combo:</div>  
  20.     <div id="combo-ct"></div>  
  21. </div>  
  22. </body>  
  23. </html>  
  24. 该文件来自教程Ext程序规划入门 的轻微修改。   
  25. iconcombo.js  
  26. /** 
  27.   * Ext.ux.IconCombo Tutorial 
  28.   * by Jozef Sakalos, aka Saki 
  29.   * http://extjs.com/learn/Tutorial:Extending_Ext_Class 
  30.   */  
  31.    
  32. // 引用本地空白文件  
  33. Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';  
  34.    
  35. // 创建程序  
  36. iconcombo = function() {  
  37.    
  38.     // 公共空间  
  39.     return {  
  40.         // public properties, e.g. strings to translate  
  41.    
  42.         // public methods  
  43.         init: function() {  
  44.             var icnCombo = new Ext.ux.IconCombo({  
  45.                 store: new Ext.data.SimpleStore({  
  46.                     fields: ['countryCode', 'countryName', 'countryFlag'],  
  47.                     data: [  
  48.                         ['US', 'United States', 'x-flag-us'],  
  49.                         ['DE', 'Germany', 'x-flag-de'],  
  50.                         ['FR', 'France', 'x-flag-fr']  
  51.                     ]  
  52.                 }),  
  53.                 valueField: 'countryCode',  
  54.                 displayField: 'countryName',  
  55.                 iconClsField: 'countryFlag',  
  56.                 triggerAction: 'all',  
  57.                 mode: 'local',  
  58.                 width: 160  
  59.             });  
  60.             icnCombo.render('combo-ct');  
  61.             icnCombo.setValue('DE');  
  62.         }  
  63.     };  
  64. }(); // end of app  
  65.    
  66. // end of file  
  67.   
  68. 我们在这个文件中创建IconCombo,以便可以进行扩展和测试。   
  69. Ext.ux.IconCombo.js  
  70. // Create创建用户的扩展(User eXtensions namespace (Ext.ux))  
  71. Ext.namespace('Ext.ux');  
  72.    
  73. /** 
  74.   * Ext.ux.IconCombo 扩展类 
  75.   * 
  76.   * @author Jozef Sakalos, aka Saki 
  77.   * @version 1.0 
  78.   * 
  79.   * @class Ext.ux.IconCombo 
  80.   * @extends Ext.form.ComboBox 
  81.   * @constructor 
  82.   * @param {Object} config 配置项参数 
  83.   */  
  84. Ext.ux.IconCombo = function(config) {  
  85.    
  86.     // 调用父类的构建函数  
  87.     Ext.ux.IconCombo.superclass.constructor.call(this, config);  
  88.    
  89. } // Ext.ux.IconCombo构建器的底部  
  90.    
  91. // 进行扩展  
  92. Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {  
  93.    
  94. }); // 扩展完毕  
  95.    
  96. // 文件底部  
  97. 运行到这一步,实际这是一个没有对Ext.form.ComboBox新加任何东西的空扩展。我们正是需要这个完成好的空扩展,再继续下一步。   
  98. Ext.ux.IconCombo.css  
  99. .x-flag-us {  
  100.     background-image: url(../img/flags/us.png);  
  101. }  
  102. .x-flag-de {  
  103.     background-image: url(../img/flags/de.png);  
  104. }  
  105. .x-flag-fr {  
  106.     background-image: url(../img/flags/fr.png);  
  107. }  
  108. 路径可能根据你所在的国旗放置目录有所不同。国旗的资源可在here下载。   
  109. Let's go  
  110. So far so good!如果你浏览iconcombo.html应该会发现一个包含三个选项的标准combo,而德国的那个是选中的...是吧?不过还没有图标...   
  111. 现在正是开始工作。在调用父类构建器之后加入下列行:   
  112. this.tpl = config.tpl ||  
  113.       '<div class="x-combo-list-item">'  
  114.     + '<table><tbody><tr>'  
  115.     + '<td>'  
  116.     + '<div class="{' + this.iconClsField + '} x-icon-combo-icon"></div></td>'  
  117.     + '<td>{' + this.displayField + '}</td>'  
  118.     + '</tr></tbody></table>'  
  119.     + '</div>'  
  120. ;  
  121. 在这一步,我们将默认combox box的模版重写为iconClsField模版。   
  122. 现在加入Ext.ux.IconCombo.css中的样式文件:   
  123. .x-icon-combo-icon {  
  124.     background-repeat: no-repeat;  
  125.     background-position: 0 50%;  
  126.     width: 18px;  
  127.     height: 14px;  
  128. }  
  129. 不错!可以测试一下了,刷新的页面,还好吧!?嗯,列表展开时那些漂亮的图标就出来了。。还有。。我们不是要在关闭时也出现图标的吗?   
  130. 在构建器中加入创建模版的过程:   
  131. this.on({  
  132.     render:{scope:this, fn:function() {  
  133.         var wrap = this.el.up('div.x-form-field-wrap');  
  134.         this.wrap.applyStyles({position:'relative'});  
  135.         this.el.addClass('x-icon-combo-input');  
  136.         this.flag = Ext.DomHelper.append(wrap, {  
  137.             tag: 'div', style:'position:absolute'  
  138.         });  
  139.     }}  
  140. });  
  141. 加入 事件render的侦听器,用于调整元素样式和创建国旗的div容器。如后按照下列方式进行扩展:   
  142. // 进行扩展  
  143. Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {  
  144.    
  145.     setIconCls: function() {  
  146.         var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);  
  147.         if(rec) {  
  148.             this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);  
  149.         }  
  150.     },  
  151.    
  152.     setValue: function(value) {  
  153.         Ext.ux.IconCombo.superclass.setValue.call(this, value);  
  154.         this.setIconCls();  
  155.     }  
  156.    
  157. }); // 扩展完毕  
  158. 新增 setIconCls函数并重写setValue函数。我们还是需要父类的setValue的方法来调用一下,接着再调用setIconCls的函数。最后,我们应该在文件Ext.ux.IconCombo.css加入下列代码:   
  159. .x-icon-combo-input {  
  160.     padding-left: 26px;  
  161. }  
  162. .x-form-field-wrap .x-icon-combo-icon {  
  163.     top: 3px;  
  164.     left: 6px;  
  165. }  
  166. 完成  
  167. 最后再刷新一下,如果一切顺利,那这个就是新的Ext.ux.IconCombo扩展! 希望你能在此基础上扩展更多的组件!   
  168. 谢谢Brian Moeskau提醒,使得能进一步精简Ext.ux.IconCombo 代码,才称得上最终版本。最终代码和CSS为:   
  169. Ext.ux.IconCombo.js  
  170. // Create user extensions namespace (Ext.ux)  
  171. Ext.namespace('Ext.ux');  
  172.    
  173. /** 
  174.   * Ext.ux.IconCombo Extension Class 
  175.   * 
  176.   * @author  Jozef Sakalos 
  177.   * @version 1.0 
  178.   * 
  179.   * @class Ext.ux.IconCombo 
  180.   * @extends Ext.form.ComboBox 
  181.   * @constructor 
  182.   * @param {Object} config Configuration options 
  183.   */  
  184. Ext.ux.IconCombo = function(config) {  
  185.    
  186.     // call parent constructor  
  187.     Ext.ux.IconCombo.superclass.constructor.call(this, config);  
  188.    
  189.     this.tpl = config.tpl ||  
  190.           '  
  191. {'   
  192.         + this.displayField   
  193.         + '}  
  194. '  
  195.     ;  
  196.    
  197.     this.on({  
  198.         render:{scope:this, fn:function() {  
  199.             var wrap = this.el.up('div.x-form-field-wrap');  
  200.             this.wrap.applyStyles({position:'relative'});  
  201.             this.el.addClass('x-icon-combo-input');  
  202.             this.flag = Ext.DomHelper.append(wrap, {  
  203.                 tag: 'div', style:'position:absolute'  
  204.             });  
  205.         }}  
  206.     });  
  207. } // end of Ext.ux.IconCombo constructor  
  208.    
  209. // extend  
  210. Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {  
  211.    
  212.     setIconCls: function() {  
  213.         var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);  
  214.         if(rec) {  
  215.             this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);  
  216.         }  
  217.     },  
  218.    
  219.     setValue: function(value) {  
  220.         Ext.ux.IconCombo.superclass.setValue.call(this, value);  
  221.         this.setIconCls();  
  222.     }  
  223.    
  224. }); // end of extend  
  225.    
  226. // end of file  
  227. Ext.ux.IconCombo.css  
  228. css  
  229. /* application specific styles */  
  230. .x-flag-us {  
  231.     background-image:url(../img/flags/us.png);  
  232. }  
  233. .x-flag-de {  
  234.     background-image:url(../img/flags/de.png);  
  235. }  
  236. .x-flag-fr {  
  237.     background-image:url(../img/flags/fr.png);  
  238. }  
  239.    
  240. /* Ext.ux.IconCombo mandatory styles */  
  241. .x-icon-combo-icon {  
  242.     background-repeat: no-repeat;  
  243.     background-position: 0 50%;  
  244.     width: 18px;  
  245.     height: 14px;  
  246. }  
  247. .x-icon-combo-input {  
  248.     padding-left: 25px;  
  249. }  
  250. .x-form-field-wrap .x-icon-combo-icon {  
  251.     top: 3px;  
  252.     left: 5px;  
  253. }  
  254. .x-icon-combo-item {  
  255.     background-repeat: no-repeat;  
  256.     background-position: 3px 50%;  
  257.     padding-left: 24px;  
  258. }  

EXT的布局(Layout)
Ext的layout布局对于建立WEB程序尤为有用。关于布局引擎(layout engine),区域管理器(region manager)的教程将分为几部分,本文是第一篇,为您介绍如何创建区域,如何增加版面到这些区域。
布局引擎(layout engine)这一功能早已在EXT前个ALPHA实现了。 Jack Slocum对于怎样环绕某一区域,给与指定区域管理的策略,和建立界面的问题,在他的第一、第二篇关于跨浏览器的WEB2.0布局功能的博客中,进行过 讨论。定义一个DOM元素的边界(edge),使之一个布局的边框(border)--这种做法使得创建“富界面”客户端UI的开发更进一大步。
布局管理器(layout manager)负责管理这些区域。布局管理的主要的用户组件是BorderLayout类。该类为EXT开发富界面的程序提供了一个切入点。 Layout的含意是划分好一些预定的区域。可用的区域分别有south, east, west, north,和center。每一个BorderLayout对象都提供这些区域但只有center要求必须使用的。如果你在单独一个区域中包含多个面 板,你可通过NestedLayoutPanel 类套嵌到BorderLayout 实例中。
注意事项:本教程的每个文件都是.html和.js格式的。教程每一步都有演示,你也可以下载这些文件在编辑器(zip格式提供在这里)中看看发生什么事。
面板(Panel)是区域管理(region management)的另外一个组件。面板提供了这么一个地方,可为您的EXT器件(widget)、加载的HTML,嵌入的IFrames、或者是你 日常在HTML页面上摆放的随便一样东西。NestedLayoutPanel也是一个面板,只不过用于链接多个BorderLayout的区域,其它的 面板包括内容面板 ContentPanel,Grid面板 GridPanel,和Tree面板 TreePanel。
简单的例子
下面的layout包含 north, south, east, west,和center的区域,而且每个区域包含一个ContentPanel,各区域之间使用得了分隔条分割开。
Java代码
  1.    
  2. var mainLayout = new Ext.BorderLayout(document.body,   
  3. {  
  4.     north: {   
  5.         split: true, initialSize: 50   
  6.     },  
  7.     south: {  
  8.         split: true, initialSize: 50   
  9.     },  
  10.     east: {   
  11.         split: true, initialSize: 100   
  12.     },   
  13.     west: {   
  14.         split: true, initialSize: 100   
  15.     },   
  16.     center: {  
  17.     }  
  18. });  
  19. 这是一个非常基本的layout,只是分配了东南西北中间的区域、分隔条、设置一下初始尺寸,并最迟定义中间区域。本例中, BorderLayout被绑定到"document.body"这个DOM元素,其实BorderLayout还可以绑定到任何一个封闭的DOM元素。定义好BorderLayout之后,我们加入ContentPanel对象(基于本例)。  
  20. mainLayout.beginUpdate();  
  21. mainLayout.add('north', new Ext.ContentPanel('north-div', {  
  22.     fitToFrame: true, closable: false  
  23. }));  
  24. mainLayout.add('south', new Ext.ContentPanel('south-div', {  
  25.     fitToFrame: true, closable: false   
  26. }));  
  27. mainLayout.add('east', new Ext.ContentPanel('east-div', {  
  28.     fitToFrame: true, closable: false  
  29. }));  
  30. mainLayout.add('west', new Ext.ContentPanel('west-div', {  
  31.     fitToFrame: true, closable: false  
  32. }));  
  33. mainLayout.add('center', new Ext.ContentPanel('center-div', {  
  34.     fitToFrame: true  
  35. }));  
  36. mainLayout.endUpdate();  

当前的例子是将ContentPanel加入到所有区域中。由调用mainLayout.beginUpdate()开始。 beginUpdate ()告诉BorderLayout对象在执行endUpate()方法之前,先不要对加入的对象排版布局。这样的好处是避免了ContentPanel有 对象加入时,导致UI的刷新,改进了整体的用户体验。执行beginUpdate()之后,加入五个ContentPanel对象到区域。所有的 ContentPanel对象(除中间的那个外),都设置是可关闭的(closbale)。所有的ContentPanel对象也都设置为自动适配它们的 父元素。最后执行endUpdate()渲染layout。
InternetExploer注意事项:BorderLayout所容纳的元素必须有一个SIZE以便正确渲染。典型地你无须为 document.body 指明size,因为document.body通常是有size的了(大多数情况,-除非你在浏览器上什么也看不到)。但是如果你将layout连同容器 放到现有的web页面上(‘可能是DIV),那么DIV的size应该先指明以便正确渲染。如下列显示正常:
好,让我们趁热打铁,看看完整的layout是怎样的。假设ext是一子目录叫做ext-1.0,父目录下面的代码。
simple.html:


   
   
    

    
    
    



   


   

   

   


   




simple.js:
Java代码
  1. Simple = function() {  
  2.     return {  
  3.         init : function() {  
  4.             var mainLayout = new Ext.BorderLayout(document.body, {  
  5.                 north: {  
  6.                     split: true, initialSize: 50  
  7.                 },  
  8.                 south: {  
  9.                     split: true, initialSize: 50  
  10.                 },  
  11.                 east: {  
  12.                     split: true, initialSize: 100  
  13.                 },  
  14.                 west: {  
  15.                     split: true, initialSize: 100  
  16.                 },  
  17.                 center: {  
  18.                 }  
  19.             });  
  20.             mainLayout.beginUpdate();  
  21.             mainLayout.add('north', new Ext.ContentPanel('north-div', {  
  22.                 fitToFrame: true, closable: false   
  23.             }));  
  24.             mainLayout.add('south', new Ext.ContentPanel('south-div', {  
  25.                 fitToFrame: true, closable: false  
  26.             }));  
  27.             mainLayout.add('east', new Ext.ContentPanel('east-div', {  
  28.                 fitToFrame: true, closable: false  
  29.             }));  
  30.             mainLayout.add('west', new Ext.ContentPanel('west-div', {  
  31.                 fitToFrame: true, closable: false  
  32.             }));  
  33.             mainLayout.add('center', new Ext.ContentPanel('center-div', {  
  34.                 fitToFrame: true  
  35.             }));  
  36.             mainLayout.endUpdate();  
  37.         }  
  38.     };  
  39. }();  
  40. Ext.EventManager.onDocumentReady(Simple.init, Simple, true);  

加入内容
上面的例子做的layout,除了可移动分割栏外,功能还不强大。需要加入些内容。有几种的办法加入内容。如果您直接加入内容到DIV中 (ContentPanel绑定的那个),ContentPanel对象会对div里面的内容进行渲染。尽管试试!我们会更改html内容加入 center-div中。
simple2.html:


   
   
    

    
    
    



   


   

   

   


   

        This is some content that will display in a panel
        when a ContentPanel object is attached to the div.
   




除此之外,还可以利用ContentPanel对象带有的function加载数据。可用的方法有几种,这里我们使用其中两 种:setContent() 与 setUrl()。setContent()允许您直接从JavaScipt程序中插入HTML。setUrl(),允许您从服务端得到数据加入 ContentPanel中。
我们原来的例子中,ContentPanel对象创建的时候是匿名的(anonymous)。这没问题,但要引用它们,你需要遍历区域管理器所分配的对象以获得引用的对象。这不是最好的办法,所有我的做法是分配一个变量给ContentPanel然后便可直接引用。
simple3.js:
Java代码
  1. Simple = function() {  
  2.     var northPanel, southPanel, eastPanel, westPanel, centerPanel;  
  3.     return {  
  4.         init : function() {  
  5.             var mainLayout = new Ext.BorderLayout(document.body, {  
  6.                 north: {   
  7.                     split: true, initialSize: 50   
  8.                 },   
  9.                 south: {   
  10.                     split: true, initialSize: 50   
  11.                 },   
  12.                 east: {   
  13.                     split: true, initialSize: 100   
  14.                 },   
  15.                 west: {   
  16.                     split: true, initialSize: 100   
  17.                 },   
  18.                 center: {   
  19.                 }  
  20.             });  
  21.             mainLayout.beginUpdate();  
  22.             mainLayout.add('north', northPanel = new Ext.ContentPanel('north-div', {   
  23.                 fitToFrame: true, closable: false   
  24.             }));  
  25.             mainLayout.add('south', southPanel = new Ext.ContentPanel('south-div', {   
  26.                 fitToFrame: true, closable: false   
  27.             }));  
  28.             mainLayout.add('east', eastPanel = new Ext.ContentPanel('east-div', {   
  29.                 fitToFrame: true, closable: false   
  30.             }));  
  31.             mainLayout.add('west', westPanel = new Ext.ContentPanel('west-div', {   
  32.                 fitToFrame: true, closable: false   
  33.             }));  
  34.             mainLayout.add('center', centerPanel = new Ext.ContentPanel('center-div', {   
  35.                 fitToFrame: true   
  36.             }));  
  37.             mainLayout.endUpdate();  
  38.             northPanel.setContent('This panel will be used for a header');  
  39.             westPanel.setContent(' ');  
  40.             centerPanel.setUrl('index.html');  
  41.             centerPanel.refresh();  
  42.         }  
  43.     };  
  44. }();  
  45. Ext.EventManager.onDocumentReady(Simple.init, Simple, true);  

我们现在从现有的页面动态加载内容。但是这里有个问题。若果内容页面积过大而撑破页面的话将没有意义了。我们提供了一些配置属性以解决这类问题。 当 fitToFrame为true时,就自动配置autoScroll。内容一旦溢出就会出现滚动条。另外一个涉及InternetExploer的问题, 是中间的内容的样式没有生效,原因是一些浏览器支持动态样式而一些不支持,要较好地解决上述问题,推荐使用Iframe标签。
用IFRAME标签做布局可灵活地处理,我们准备在DOM中直接操纵IFRAME.这里IFRAME成为面板的容器,以填入中间区域的内容
设置一下 IFRAME的滚动条并放到中间的页面。.
simple4.html:




   
   
    
    

    
    


   

   


   

   

   

       
   




simple4.js:
Java代码
  1. Simple = function() {  
  2.     var northPanel, southPanel, eastPanel, westPanel, centerPanel;  
  3.     return {  
  4.         init : function() {  
  5.             var mainLayout = new Ext.BorderLayout(document.body, {  
  6.                 north: {   
  7.                     split: true, initialSize: 50   
  8.                 },   
  9.                 south: {   
  10.                     split: true, initialSize: 50   
  11.                 },   
  12.                 east: {   
  13.                     split: true, initialSize: 100   
  14.                 },   
  15.                 west: {   
  16.                     split: true, initialSize: 100   
  17.                 },   
  18.                 center: {   
  19.                 }  
  20.             });  
  21.             mainLayout.beginUpdate();  
  22.             mainLayout.add('north', northPanel = new Ext.ContentPanel('north-div', {   
  23.                 fitToF  
  24.  

zhuan:http://programming.javaeye.com/blog/167808

posted on 2009-07-09 09:34 找个美女做老婆 阅读(4711) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

公告

本blog已经搬到新家了, 新家:www.javaly.cn
 http://www.javaly.cn

常用链接

留言簿(5)

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜