文档库 最新最全的文档下载
当前位置:文档库 › 中文手册

中文手册

EXT 中文手册

前言

本手册所有内容均粘贴自互联网,如有错误,请多见谅。

目录

EXT 中文手册 (1)

EXT简介 (4)

目錄 (4)

下载Ext (5)

开始! (5)

Element:Ext的核心 (5)

获取多个DOM的节点 (6)

响应事件 (6)

使用Widgets (8)

使用Ajax (10)

EXT源码概述 (12)

揭示源代码 (12)

发布Ext源码时的一些细节 (13)

我应该从哪里开始? (14)

适配器Adapters (14)

核心Core (14)

Javascript中的作用域(scope) (14)

事前准备 (14)

定义 (14)

正式开始 (15)

window对象 (15)

理解作用域 (16)

变量的可见度 (16)

EXT程序规划入门 (17)

事前准备 (17)

需要些什么? (17)

applayout.html (17)

applayout.js (18)

公开Public、私有Private、特权的Privileged? (20)

重写公共变量 (22)

重写(Overriding)公共函数 (22)

DomQuery基础 (23)

DomQuery基础 (23)

扩展EXT组件 (30)

文件的创建 (30)

Let's go (34)

完成 (36)

EXT的布局(Layout) (38)

简单的例子 (39)

加入内容 (42)

开始使用Grid (52)

步骤一定义数据(Data Definition) (52)

步骤二列模型(Column Model) (53)

Grid组件的简易分页 (54)

G r i d数据 (54)

怎么做一个分页的G r i d (55)

分页栏T o o l b a r (55)

EXT Menu组件 (56)

创建简易菜单 (56)

各种I t e m的类型 (58)

I t e m属性 (58)

在U I中摆放菜单 (58)

M e n u的分配方式: (59)

练一练 (61)

动态添加菜单按钮到T o o l b a r (61)

更方便的是 (62)

下一步是 (62)

模板(Templates)起步 (62)

第一步您的HTML模板 (62)

第二步,将数据加入到模板中 (63)

下一步 (63)

学习利用模板(Templates)的格式化功能 (63)

正式开始 (63)

下一步 (65)

事件处理 (65)

非常基础的例子 (65)

处理函数的作用域 (65)

传递参数 (66)

类设计 (66)

对象创建 (66)

使用构造器函数 (67)

方法共享 (67)

表单组件入门 (68)

表单体 (68)

创建表单字段 (68)

完成表单 (69)

下一步 (70)

为一个表单填充或提交数据 (70)

让我们开始吧 (70)

读取我们的数据 (71)

EXT中的继承 (72)

补充资料 (73)

Ext 2 概述 (73)

组件模型 Component Model (75)

容器模型Container Model (79)

布局 Layouts (80)

Grid (83)

XTemplate (83)

DataView (84)

其它新组件 (84)

EXT2简介 (85)

下载Ext (85)

开始! (86)

Element:Ext的核心 (86)

获取多个DOM的节点 (87)

响应事件 (87)

使用Widgets (89)

編輯使用Ajax (92)

TabPanel基础 (95)

Step 1: 创建 HTML 骨架 (95)

Step 2: Ext结构的构建 (96)

Step 3: 创建Tab控制逻辑 (98)

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

o7.1 PHP

o7.2 https://www.wendangku.net/doc/ea13936000.html,

o7.3 Cold Fusion

下载Ext

如果你未曾下载过,那应从这里下载最新版本的Ext https://www.wendangku.net/doc/ea13936000.html,/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的位置中加入:

myDiv.highlight(); //黄色高亮显示然后渐退

myDiv.addClass('red'); // 添加自定义CSS类(在ExtStart.css定义)

myDiv.center(); //在视图中将元素居中

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,编辑下列的代

码:

Ext.onReady(function() {

function(){

Ext.get('myButton').on('click',

alert("You clicked the button");

});

});

加载好页面,代码依然会执行,不过区别是,包含alert()的function是已定义好的,但它不会立即地被执行,是分配到按钮的单击事件中。用浅显的文字解释,就是:获取ID为'myDottom'元素的引用,监听任何发生这个元素上被单击的情况,并分配一个function,以准备任何单击元素的情况。

正路来说,Element.select也能做同样的事情,即作用在获取一组元素上。下一例中,演示了页面中的某一段落被单击后,便有弹出窗口:

Ext.onReady(function() {

Ext.select('p').on('click', function() {

alert("You clicked a paragraph");

});

});

这两个例子中,事件处理的function均是简单几句,没有函数的名称,这种类型函数称为“匿名函数(anonymous function)”,即是没有名的的函数。你也可以分配一个有名字的event handler,这对于代码的重用或多个事件很有用。下一例等效于上一例:

Ext.onReady(function() {

var paragraphClicked = function() {

alert("You clicked a paragraph");

}

paragraphClicked);

Ext.select('p').on('click',

});

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

Ext.onReady(function() {

var paragraphClicked = function(e) {

Ext.get(e.target).highlight();

}

paragraphClicked);

Ext.select('p').on('click',

});

注意得到的e.target是DOM节点,所以我们首先将其转换成为EXT的Elemnet元素,然后执行欲完成的事件,这个例子中,我们看见段落是高亮显示的。

使用Widgets

(Widget原意为“小器件”,现指页面中UI控件)

除了我们已经讨论过的核心JavaScript库,当前的Ext亦包括了一系列的最前端的JavaScirptUI组件库。文本以一个常用的widget为例子,作简单的介绍。

MessageBox

比起略为沉闷的“HelloWolrd”消息窗口,我们做少许变化,前面我们写的代码是,单击某个段落便会高亮显示,现在是单击段落,在消息窗口中显示段落内容出来。

在上面的paragraphClicked的function中,将这行代码:

Ext.get(e.target).highlight();

替换为:

var paragraph = Ext.get(e.target);

paragraph.highlight();

Ext.MessageBox.show({

title: 'Paragraph Clicked',

paragraph.dom.innerHTML,

msg:

width:400,

Ext.MessageBox.OK,

buttons:

paragraph

animEl:

});

这里有些新的概念需要讨论一下。在第一行中我们创建了一个局部变量(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中全部语句:

Ext.onReady(function() {

var myData = [

['Apple',29.89,0.24,0.81,'9/1

12:00am'],

12:00am'],

['Ext',83.81,0.28,0.34,'9/12

12:00am'],

['Google',71.72,0.02,0.03,'10/1

['Microsoft',52.55,0.01,0.02,'7/4

12:00am'],

12:00am']

['Yahoo!',29.01,0.42,1.47,'5/22

];

var ds = new Ext.data.Store({

proxy: new Ext.data.MemoryProxy(myData),

reader: new Ext.data.ArrayReader({id: 0}, [

'company'},

{name:

{name: 'price', type: 'float'},

{name: 'change', type: 'float'},

{name: 'pctChange', type: 'float'},

{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'} ])

});

ds.load();

var colModel = new Ext.grid.ColumnModel([

{header: "Company", width: 120, sortable: true, dataIndex: 'company'},

{header: "Price", width: 90, sortable: true, dataIndex: 'price'},

{header: "Change", width: 90, sortable: true, dataIndex: 'change'},

{header: "% Change", width: 90, sortable: true, dataIndex: 'pctChange'},

{header: "Last Updated", width: 120, sortable: true,

renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}

]);

var grid = new Ext.grid.Grid('grid-example', {ds: ds, cm: colModel});

grid.render();

grid.getSelectionModel().selectFirstRow();

});

这看上去很复杂,但实际上加起来,只有七行代码。第一行创建数组并作为数据源。实际案例中,

你很可能从数据库、或者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中加入

下列代码,但这必须要访问服务器):

Name:

接着,我们加入这些处理交换数据的JavaScript代码到文件ExtStart.js中(用下面的代码覆盖):Ext.onReady(function(){

Ext.get('oKButton').on('click',

function(){

var msg = Ext.get('msg');

msg.load({

url: [server url], //换成你的URL

params: 'name=' + Ext.get('name').dom.value,

'Updating...'

text:

});

msg.show();

});

});

这种模式看起来已经比较熟悉了吧!先获取按钮元素,加入单击事件的监听。在事件处理器中(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

echo 'From Server: '.$_GET['name'];

}

?>

https://www.wendangku.net/doc/ea13936000.html,

protected void Page_Load(object sender, EventArgs e)

{

if (Request["name"] != null)

{

Response.Write("From Server: " + Request["name"]);

Response.End();

}

}

Cold Fusion

From Server: #https://www.wendangku.net/doc/ea13936000.html,#

最后一个关于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

/*

* Ext JS Library 1.1

* Copyright(c) 2006-2007, Ext JS, LLC.

* licensing@https://www.wendangku.net/doc/ea13936000.html,

*

* https://www.wendangku.net/doc/ea13936000.html,/license

*/

Ext.DomHelper=function(){var _1=null;var _2=/^(?:br|frame...

Ext.Template=function(_1){if(_1 instanceof Array){_1...

...

接着看下去的是ext-core-debug.js(注意在文件名后面加上-debug的JS文件),我会发现是全部已格式化好的源代码。这个文件是配合调时器所使用的,像Firebug的工具能够可以让你一步一步地、一行一行地调试代码。你也会发现文件的体积将近大了一倍之多,这便是没有压缩或混淆的缘故。

ext-core-debug.js

/*

* Ext JS Library 1.1

* Copyright(c) 2006-2007, Ext JS, LLC.

* licensing@https://www.wendangku.net/doc/ea13936000.html,

*

* https://www.wendangku.net/doc/ea13936000.html,/license

*/

Ext.DomHelper = function(){

var tempTableEl = null;

var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;

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注):

i = 44;

function fn2() {

var i = 55;

alert(i);

}

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

"https://www.wendangku.net/doc/ea13936000.html,/TR/html4/loose.dtd">

Application Layout Tutorial

开头的两行声明了文档的类型。程序可以不用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(当前空)和结束标签。

文档的解说就说到这儿了。

/**

* Application Layout

* by Jozef Sakalos, aka Saki

* https://www.wendangku.net/doc/ea13936000.html,/learn/Tutorial:Application_Layout_for_Beginners_(Chinese)

*/

// 填充图片的本地引用

Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';

// 创建命名空间

https://www.wendangku.net/doc/ea13936000.html,space('myNameSpace');

// 创建应用程序

myNameSpace.app = function() {

// 元素还没创建,未能访问

// 私有变量

// 私有函数

// 公共空间

return {

// 公共的属性,如,要转换的字符串

// 公共方法

init: function() {

alert('应用程序初始化成功。');

}

};

}(); // 程序底部

// 文件底部

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

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

整段代码的重点是,我们创建了myNameSpace对象的属性app,其值是一个函数立刻运行之后的返回值。

如果运行我们的代码:

var o = function() {

return {p1:11, p2:22};

}();

实际上我们创建了一个匿名函数(没有名字的函数),经过解释(预编译?)之后让它立刻运行(注意函数后面的())。最后将函数返回的对象(注意此时是一个object变量)分配到变量o。我们的程序便是这种思路去写的。

你可以把私有变量和私有函数直接定义在function和return这两个声明之间,但是请切记:此时不能访问任何html页面中的元素,那会导致错误,因为这段代码在加载时页面的head中就运行了,而这时候html页面中的其它元素还没有被加载进来。

另外一方面,函数init,是由匿名函数返回的对象的一个方法而已。它会在文档全部加载后才运行。换言之整个DOM树已经是可用的了。

一切都还好吧~如果能正确运行https://www.wendangku.net/doc/ea13936000.html,/applayout/applayout.html,不出现什么错误的话将出现一个警告。

接下来是利用这个空白的模板,讨论本文的重点。

公开Public、私有Private、特权的Privileged?

让我们加入一些有趣内容到程序中去吧。在页面applayout.html的body标签中加入:

空白的div会当作按钮的容器来使用。然后在applayout.js加入下来代码:

/**

* Application Layout

* by Jozef Sakalos, aka Saki

* https://www.wendangku.net/doc/ea13936000.html,/learn/Tutorial:Application_Layout_for_Beginners_(Chinese)

*/

// 填充图片的本地引用

Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';

// 创建命名空间

相关文档