Tutorial:Extending Ext2 Class (Chinese)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: 本文为您介绍扩展EXT组件类所需的几个步骤。
Author: Jozef Sakalos(译者:Frank Chueng)
Published: January 2, 2008
Ext Version: 2.0+
Languages: en.png Englishkr.png Koreancn.png Chinese

Contents

[hide]

实现的目的

预期将是这样的IconCombo
预期将是这样的IconCombo

要创建的扩展是一个在文字前面能够显示图标的这么一个Ext.form.Combobox。将其中一个功能举例来说,就是要在一块选择里,国家名称连同国旗一并出现。

我们先给扩展起个名字,就叫Ext.ux.IconCombo

A note for those who were used to Ext 1.x

Extending Ext classes has not been difficult in Ext 1.x but it is even easier in Ext 2.x and the whole matter has not dramatically changed. You can even use the same procedure in Ext 2.x as you have used in Ext 1.x. However, every line of code you don't need to type contributes to code maintainability, readability and reduces number of possible bugs. Therefore, I'll show the easiest, simplest and shortest method here.

文件的创建

首要的步骤是准备好开发中将会使用的文件。需下列文件:

  • iconcombo.html: 新扩展将会使用的 html markup
  • iconcombo.js: 程序javascript代码
  • Ext.ux.IconCombo.js: 扩展的javascript文件
  • Ext.ux.IconCombo.css: 扩展样式表

iconcombo.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">
    <link rel="stylesheet" type="text/css" href="Ext.ux.IconCombo.css">
    <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
    <script type="text/javascript" src="iconcombo.js"></script>
    <!-- A Localization Script File comes here -->
    <script type="text/javascript">Ext.onReady(iconcombo.init, iconcombo);</script>
    <title>Ext.ux.IconCombo Tutorial</title>
</head>
<body>
<div style="position:relative;width:300px;top:24px;left:64px;font-size:11px">
    <div>Icon combo:</div>
    <div id="combo-ct"></div>
</div>
</body>
</html>

该文件来自教程Ext程序规划入门 的轻微修改。

iconcombo.js

/**
  * Ext.ux.IconCombo Tutorial
  * by Jozef Sakalos, aka Saki
  * http://extjs.com/learn/Tutorial:Extending_Ext_Class
  */
 
// 引用本地空白文件
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
// 创建程序
iconcombo = function() {
 
    // 公共空间
    return {
        // public properties, e.g. strings to translate
 
        // public methods
        init: function() {
            var icnCombo = new Ext.ux.IconCombo({
                store: new Ext.data.SimpleStore({
                    fields: ['countryCode', 'countryName', 'countryFlag'],
                    data: [
                        ['US', 'United States', 'x-flag-us'],
                        ['DE', 'Germany', 'x-flag-de'],
                        ['FR', 'France', 'x-flag-fr']
                    ]
                }),
                valueField: 'countryCode',
                displayField: 'countryName',
                iconClsField: 'countryFlag',
                triggerAction: 'all',
                mode: 'local',
                width: 160
            });
            icnCombo.render('combo-ct');
            icnCombo.setValue('DE');
        }
    };
}(); // end of app
 
// end of file


我们在这个文件中创建IconCombo,以便可以进行扩展和测试。

Ext.ux.IconCombo.js

// Create创建用户的扩展(User eXtensions namespace (Ext.ux))
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo 扩展类
  *
  * @author Jozef Sakalos, aka Saki
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config 配置项参数
  */
Ext.ux.IconCombo = function(config) {
 
    // 调用父类的构建函数
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
} // Ext.ux.IconCombo构建器的底部
 
// 进行扩展
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
}); // 扩展完毕
 
// 文件底部

运行到这一步,实际这是一个没有对Ext.form.ComboBox新加任何东西的空扩展。我们正是需要这个完成好的空扩展,再继续下一步。

Ext.ux.IconCombo.css

.x-flag-us {
    background-image: url(../img/flags/us.png);
}
.x-flag-de {
    background-image: url(../img/flags/de.png);
}
.x-flag-fr {
    background-image: url(../img/flags/fr.png);
}

路径可能根据你所在的国旗放置目录有所不同。国旗的资源可在here下载。

Let's go

So far so good!如果你浏览iconcombo.html应该会发现一个包含三个选项的标准combo,而德国的那个是选中的...是吧?不过还没有图标...

现在正是开始工作。在调用父类构建器之后加入下列行:

this.tpl = config.tpl ||
      '<div class="x-combo-list-item">'
    + '<table><tbody><tr>'
    + '<td>'
    + '<div class="{' + this.iconClsField + '} x-icon-combo-icon"></div></td>'
    + '<td>{' + this.displayField + '}</td>'
    + '</tr></tbody></table>'
    + '</div>'
;

在这一步,我们将默认combox box的模版重写为iconClsField模版。

现在加入Ext.ux.IconCombo.css中的样式文件:

.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}

不错!可以测试一下了,刷新的页面,还好吧!?嗯,列表展开时那些漂亮的图标就出来了。。还有。。我们不是要在关闭时也出现图标的吗?

在构建器中加入创建模版的过程:

this.on({
    render:{scope:this, fn:function() {
        var wrap = this.el.up('div.x-form-field-wrap');
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('x-icon-combo-input');
        this.flag = Ext.DomHelper.append(wrap, {
            tag: 'div', style:'position:absolute'
        });
    }}
});

加入 事件render的侦听器,用于调整元素样式和创建国旗的div容器。如后按照下列方式进行扩展:

// 进行扩展
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // 扩展完毕

新增 setIconCls函数并重写setValue函数。我们还是需要父类的setValue的方法来调用一下,接着再调用setIconCls的函数。最后,我们应该在文件Ext.ux.IconCombo.css加入下列代码:

.x-icon-combo-input {
    padding-left: 26px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 6px;
}

完成

最后再刷新一下,如果一切顺利,那这个就是新的Ext.ux.IconCombo扩展! 希望你能在此基础上扩展更多的组件!

谢谢Brian Moeskau提醒,使得能进一步精简Ext.ux.IconCombo 代码,才称得上最终版本。最终代码和CSS为:

Ext.ux.IconCombo.js

// Create user extensions namespace (Ext.ux)
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo Extension Class
  *
  * @author  Jozef Sakalos
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config Configuration options
  */
Ext.ux.IconCombo = function(config) {
 
    // call parent constructor
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
    this.tpl = config.tpl ||
          '<div class="x-combo-list-item x-icon-combo-item {' 
        + this.iconClsField 
        + '}">{' 
        + this.displayField 
        + '}</div>'
    ;
 
    this.on({
        render:{scope:this, fn:function() {
            var wrap = this.el.up('div.x-form-field-wrap');
            this.wrap.applyStyles({position:'relative'});
            this.el.addClass('x-icon-combo-input');
            this.flag = Ext.DomHelper.append(wrap, {
                tag: 'div', style:'position:absolute'
            });
        }}
    });
} // end of Ext.ux.IconCombo constructor
 
// extend
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // end of extend
 
// end of file

Ext.ux.IconCombo.css

/* application specific styles */
.x-flag-us {
    background-image:url(../img/flags/us.png);
}
.x-flag-de {
    background-image:url(../img/flags/de.png);
}
.x-flag-fr {
    background-image:url(../img/flags/fr.png);
}
 
/* Ext.ux.IconCombo mandatory styles */
.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}
.x-icon-combo-input {
    padding-left: 25px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 5px;
}
.x-icon-combo-item {
    background-repeat: no-repeat;
    background-position: 3px 50%;
    padding-left: 24px;
}
posted @ 2008-05-23 23:56 meetrice 阅读(542) 评论(0) 编辑

Tutorial:TabPanel Basics (Chinese)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: 对Tab标签页的使用作简单地介绍
Author: Robin Percy (译者:Frank Cheung)
Published: 2007年十一月十五号
Ext Version: 2.0
Languages: en.png Englishcn.png Chinesede.png German

Contents

[hide]

摘要

这份教程目的在于对TabPanel类进行一次快速介绍。所提及的知识都是来自我对TabPanel范例、Ext源码和API文档的学习。到本文最后,你应该完成好一个Tab Panel,这个TabPanel能够:

  • 创建新tab,其内容来自一个URL。
  • 判断某个tab是否存在,有的话加载新内容。

步骤 1: 创建 HTML 骨架

我们将会用下列HTML,和Ext一齐构建一个基本的结构。复制这些内容到一个叫tptut.html的文件,并要求是运行在服务端的,当然 也要保证ext-all.css, ext-base.js, 和 ext-all.js这些Ext安装路径的正确。然后按照以下步骤创建tab_actions.js:

<html>
<head>
<title>TabPanel教程</title>
<!-- Ext CSS and Libs -->
<link rel="stylesheet" type="text/css"	href="../include/ext2/resources/css/ext-all.css" />
<script type="text/javascript"	src="../include/ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../include/ext2/ext-all.js"></script>
 
<!-- Custom CSS and Libs -->
<script type="text/javascript" src="./tab_actions.js"></script>
<style>
#actions li {
	margin:.3em;
}
#actions li a {
	color:#666688;
	text-decoration:none;
}
</style>
</head>
<body>
 
 
<ul id="actions" class="x-hidden">
	<li>
		<a id="use" href="#">Use Existing Tab</a>
	</li>
	<li>
		<a id="create" href="#">Create New Tab</a>
	</li>
</ul>
 
<div id="tabs"></div>
</body>
</html>

以上代码有两个地方的元素需要注意。我们将使用"actions"(动作列表)这种简易的实现来执行tab的创建。"tabs"的那个div将用于Tab面板中第一个默认tab的容器。

Step 2: Ext结构的构建

在刚才那个目录中创建一个文文件。就叫做作tab_actions.js,加入下面JavaScript:


Ext.onReady(function(){
   // 包含actions的菜单
    var tabActions = new Ext.Panel({
    	frame:true,
    	title: 'Actions',
    	collapsible:true,
    	contentEl:'actions',
    	titleCollapse: true
    });
 
    // 保持actions菜单的父面板
    var actionPanel = new Ext.Panel({
    	id:'action-panel',
    	region:'west',
    	split:true,
    	collapsible: true,
    	collapseMode: 'mini',
    	width:200,
    	minWidth: 150,
    	border: false,
    	baseCls:'x-plain',
    	items: [tabActions]
    });
 
    // 主面板(已有tab)
    var tabPanel = new Ext.TabPanel({
		region:'center',
		deferredRender:false,
		autoScroll: true, 
		margins:'0 4 4 0',
		activeTab:0,
		items:[{
			id:'tab1',
			contentEl:'tabs',
    		title: 'Main',
    		closable:false,
    		autoScroll:true
		}]
    });
 
    //  配置视图viewport
    viewport = new Ext.Viewport({
           layout:'border',
           items:[actionPanel,tabPanel]});
});

上面的代码被套上一个Ext.onReady的函数,以防止页面元素未全部加载就执行代码了。接着要做的事情是将我们的动作列表(Action list)转换到名字为tabActions的那个面板,该命名是由contentEl (content element)(内容元素)这个配置项参数所指定的。

接着,创建一个父面板actionPanel来保持菜单面板。我们已tabActions 作为一个item项的参数。由于actionPanel会由视图Viewport的LayoutManager来页面定位,所以我们须在配置项对象中指定一个区域。

第三个步骤是创建TabPanel(Tab面板)本身。我们想在页面居中,即是对应于视图的中部。还要将一系列的tab配置项对象参数传入到面板中。在这里例子中,参与内置渲染的只有一个tab,但是多个也是可以的。如能确定每个面板在页面上能够被当作容器使用,便可以成为该数组的元素。像当前的情况,我们是把tabs作为第一个面板的内容元素。 要注意,我们这指出了tab的Id。这就是我们稍后获取的tab的依据。

最后,我们设置视图, 用于浏览器可视区域的控制。 所需要做的就是指定一个布局(layout)和什么要显示的组件。组件已经由视图的LayoutMangager(视图管理器)配置好适合放置的区域。

这时,你应该在浏览器观察到,包含Acitons菜单的两个格式化列在左边,tab面板占据了屏幕的其余位置。

Step 3: 创建Tab控制逻辑

现在我们所需的元素已经创建好了, 可以增加Tab面板的创建(creating)和更新(updating)方法。 在当前目录中新建三个页面以便我们的测试:

  • loripsum.html
  • sample0.html
  • sample1.html

这三分文件的实际内容无关紧要, 但最好是每份的内容应该有所不同,好让tab加载内容后区别开来。

打开tab_actions.js,在viewport创建的位置插入下列代码:

// 在中间的面板加入tab
    function addTab(tabTitle, targetUrl){
        tabPanel.add({
	    title: tabTitle,
	    iconCls: 'tabs',
	    autoLoad: {url: targetUrl, callback: this.initSearch, scope: this},
	    closable:true
	}).show();
    }
 
    // 更新tab内容,如不存在就新建一个
    function updateTab(tabId,title, url) {
    	var tab = tabPanel.getItem(tabId);
    	if(tab){
    		tab.getUpdater().update(url);
    		tab.setTitle(title);
    	}else{
    		tab = addTab(title,url);
    	}
    	tabPanel.setActiveTab(tab);
    }
 
    // 映射连接的id到函数
    var count = 0;
    var actions = {
    	'create' : function(){
    		addTab("New Tab",'loripsum.html');
    	},
    	'use' : function(){
    		// 演示页之间的轮换
    		updateTab('tab1','替换' + count + ' 次','sample'+(count%2)+'.html');
    		count++;	    		
    	}
    };
 
    function doAction(e, t){
    	e.stopEvent();
    	actions[t.id]();
    }
 
    // body初始化后,viewport setup过后才能执行下面的代码
    actionPanel.body.on('mousedown', doAction, null, {delegate:'a'});

函数addTab(...) 需要标题title和URL字符串两个参数,然后传递到tabPanel.add(...)里的配置项对象。 这会返回创建好的面板对象,上面的代码立即调用了show()方法显示内容。

函数updateTab(...) 需要多个tabId的参数,以便能检测这个tab是否存在。如果是,面板会获取Updater进行面板内容的更新。若然不是,会调用addTab(...)创建tab。

最后一个步骤, 增加一个actionPanel的监听器,来响应选区动作之后的事件后,执行相应的函数。先要说明的是,actions是一创建好的对象,对象可被认为是一种哈希表(HashTable)或是字典(Dictionary),一一映射了动作和方法两者。注意“键key”对应于HTML list项。 由于方法比较简单,我们就直接这里写好了。变量counter用于清晰显示tab之间的切换,没有其他特定的功能。


事件处理器(event handler)doAction(...)执行时会有两个参数传入:事件对象和目标对象,actions函数查找目标对象的id然后执行相应的方法。 当任意一个actionPanel's的组件被按下,将会触发mousedown的事件,侦听器立即通知已登记的事件处理器doAction(...)运行。 被按下的那个组件便是事件对象的目标。

总结

现在刷新tptut.html看看,已经是完成好的例子了。

点击Use Existing Tab的连接会更新第一个tab的内容。Create new Tab会创建一个新的已是按下的tab。 更多资讯,请参阅Tab标签页进阶范例

posted @ 2008-05-23 23:51 meetrice 阅读(893) 评论(0) 编辑

Tutorial:Events Explained

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: This tutorial will explain what events are and how they are used in Ext.
Author: Jozef Sakalos, aka Saki
Published: May 18, 2008
Ext Version: 2.0+
Languages: en.png English

Contents

[hide]

Historical Background

Most likely many of you who will read this article do not remember times of Fortran language and computers that were fed with tons of punch cards to have some some job done.

The main purpose of computers at that time was to compute something really; that is not true anymore because computers are used for getting computational result very rarely at schools or scientific institutions nowadays.

How did it work at that time? If you wanted a computer to run a program you went to a shelf with your punched cards, you found the drawer with the stack of them, fed them through card reader and the computer started your program.

First task was to ask for user inputs and once you filled them in the program computed the result, printed it and ended. Easy, straightforward, "single thread" job.

Events Introduced

With the invent of GUI and Mouse this concept of load-run-end just couldn't work anymore as we needed some infinite loop that would wait for user actions (mouse movement and clicks) and that would process them to execute the required actions.

I has became clear very soon that putting the code that processes these action directly in that loop is the route to nowhere so the Event driven programming was born.

Event Definition

Event is a message, a function call, generated by one (part of) program, the event source, that notifies another (part of) program, the event listener, that something happened. Events are generated as responses to user actions or to state changes of the event source.

The event source is independent of event listeners and it generates events also if nobody listens or even if there is no listener defined. The viewpoint of our infinite loop would be: "I'm informing everybody that user moved the mouse to position [x,y] and I do not care who listens, if anybody."

The viewpoint of the listener would be: "Let me know when user moves the mouse, I need to do something with it."

Events in Ext

There are two main "sorts" of events in Ext: DOM events and JavaScript, or software, events.

DOM Events

Browsers that display (X)HTML pages already have our "infinite loop" that watches user actions and fires events if these actions are occurring on DOM elements. Before Ext we were used to install event listeners on DOM elements this way:

<div id="mydiv" onclick="alert('You clicked me')">Click me!</div>

Ext.Element wraps DOM elements together with their events so now we install the same event handlers this way:

Ext.get('mydiv').on('click', function() {alert('You clicked me');});

It can be said that DOM events are "passed-through" from DOM through Ext.Element to listeners.

JavaScript Events

Now, DOM elements are not only possible event sources; it is quite easy to implement event source logic and event listener installation to any JavaScript object. But, what could it be good for?

Imagine that you have a complex component such as grid. If you had only DOM events, the handling of user actions such as column move would be extremely difficult. You would need to listen to DOM elements, process mouse clicks, moves, calculate from where to where the column has been moved, etc. If would be much easier if grid component would do all this dirty work for you and, after everything has be done, just informed you: "User moved column 3 to position 1."

That is exactly what grid does: it fires JavaScript events that inform potential listeners what has happened to it. The same is true for another Ext components. Form validation events, Panel resize events, Tree expand/collapse events can serve as examples, to name a few.

How do I listen to events?

If you have an object of Ext class, for example Panel, and you need to do some action when panel resizes you would install a listener to implement your action:

// create panel
var myPanel = new Ext.Panel({...});
 
// install resize event listener
myPanel.on('resize', function(panel, w, h) {
    alert('Panel resized to ' + w + 'x' + h);
});

From this point on, whenever the panel myPanel is resized your function is called so you can do your actions.

How do I create event source?

Events related functionality is implemented in Ext.util.Observable class so if you want your extension to be an event source just extend Observable. Also, if you extend a class that is already descendant of Observable (Panel, Grid, Form, Tree, etc), your extension is automatically the event source.

Events fired by your extension are events fired by parent class(es).

Custom Events

It happens very often that you need add new events, for example you create Employee class and Organization Chart class and you implement drag&drop assignment/dismissal of employee to/from a position. I would come handy to fire event assigned and dismissed, wouldn't it?

We could listen to these events and the listeners could send e-mails to the employee informing him that he has been assigned to a position or dismissed from it.

We do it this way:

OrgChart = Ext.extend(Ext.Panel, {
    initComponent:
function() {
        
// call parent init component
        OrgChart.superclass.initComponent.apply(this, arguments);
 
        
// add custom events
        addEvents('assigned''dismissed');
    }

 
    ,assign:
function(employee, position) {
        
// do whatever is necessary to assign the employee to position
 
        
// fire assigned event
        this.fireEvent('assigned'this, employee, position);
    }

 
    ,dismiss:
function(empoyee, position) {
        
// do whatever is necessary to dismiss employee from position
 
        
// fire dismissed event
        this.fireEvent('dismissed'this, employee, position);
    }

}
);

In the initComponent function we inform Observable class that we are going to fire our new events so it can do all necessary setup.

Note: We do not extend Observable directly here but Panel, what we extend, does. Panel's inheritance chain is: Observable -> Component -> BoxComponent -> Container -> Panel.

And in assign and dismiss functions we fire our events after all assign/dismiss job has been done with signature (arguments) of our choice.

When we fireEvent, Observable looks if there are some listeners to this event and calls all listeners with arguments we supplied in fireEvent call. If there is no listener it just does nothing.

Summary

  • event is a message sent (fired) by an event source to inform listeners that something happened
  • event source is an object that can fire events
  • event listener is a function that is called when event source fires an event
  • to listen to events we use on function to install an event listener
  • to create an event source we extend Observable class, addEvents and fireEvent

Enjoy firing your events and listening to them!

Further Reading

posted @ 2008-05-23 23:49 meetrice 阅读(435) 评论(0) 编辑
posted @ 2008-05-23 23:48 meetrice 阅读(125) 评论(0) 编辑
posted @ 2008-05-23 23:47 meetrice 阅读(157) 评论(0) 编辑

Tutorial:Xtype defined (Chinese)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: 本教程为大家解释xtype的含义。
Author: Jozef Sakalos(译者:Frank Cheung)
Published: 2008五月九号
Ext Version: 2.0+
Languages: en.png Englishcn.png Chinese

Contents

[hide]

序言

根据我在EXT论坛上的观察,xtype用起来的时候疑惑会比较多。甚至有些人根本忽略xtype,或者不清楚它是什么。所以我决定阐述一下这个xtype的概念。

定义

xtype就是一个代表类(Class)的标识名字。

譬如,你有这个类,名字是Ext.ux.MyGrid。正常情况下你需要用这个名字来实例化这个类(创建类的对象)。

除了类名外,你还可以这样登记类的xtype

Ext.reg('mygrid', Ext.ux.MyGrid);

其中xtypemygrid 而类名的一般形式是Ext.ux.MyGrid。上面的语句登记了新的xtype,换种说法说,xtype mygrid 与类 Ext.ux.MyGrid是连在一起的。

到底有什么好处?

试想一下,你手头上的是一个大型的项目,为了响应用户的操作,程序里面包含者大量的对象(windows、forms、grids)。用户点击图标或按钮,就会新建一个窗体,窗体里面又有grid,最终在屏幕上渲染出来。

嗯,我们回到Ext2.x之前的编码,那时候我们实例化所有对象是页面第一次加载后就进行的(程序代码第一次的运行)。在客户端内存中,Ext.ux.MyGrid类的对象已经存在,等待用户的点击。同样是这个grid,假设你上百个的实例,...是多么浪费宝贵的资源啊!很多grid其实用户未必会点击让它出现。

延时实例化

如果你使用xtype,那么在内存中的仅仅是一个配置项对象,像:

{xtype:'mygrid", border:false, width:600, height:400, ...}

消耗没有复杂的实例对象来得大。

嗯,用户点击按钮或图标会怎么样呢?Ext会辨认出它是一个准备要渲染的grid但不立刻实例化,Ext在ComponentMgr的帮忙下明白这么一回事:“如果我要实例化xtype mygrid的对象,我就知道要创建的实际是类Ext.ux.MyGrid的对象”。即如下列代码:


create : function(config, defaultType){
    return new types[config.xtype || defaultType](config);
}

等价于:

return new Ext.ux.MyGrid(config);

然后实例化grid,进行渲染和显示。谨记:需要的时候才实例化

posted @ 2008-05-23 23:45 meetrice 阅读(559) 评论(0) 编辑

Tutorial:Localizing Ext (Chinese)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: 如何本地化ext的教程
Author: Jozef Sakalos(译者:Frank Cheung)
Published: March 9, 2008
Ext Version: 2.0+
Languages: en.png Englishkr.png Koreancn.png Chinese

Contents

[hide]

引言

如果你是英语的用户就不必做任何本地化的工作了,这篇教程是为非英语用户所准备的,好像一般的用户,开发主管,业务员等,他们的外语可能稍逊,这样就需要你对如何本地化ext的整个流程了解一番了。

慢慢开始

如果你曾浏览Ext 2.x目录的树状结构,你就会发现source/locale的目录(或SVN目录的src/locale)。此目录包含了Ext本地化类。先不长篇大论地讲太多概念的东西,我们应了解如何先使用。


下面的一个例子就是使用了本地化的ext,但是不是在ext同一个目录下的。因此通常的,你需要调整head标签内的路径,以正确指向Ext的安装目录。尤其注意本地化的那个目录路径。

把你服务器的路径Copy and paste到相应文件路径中:

注意: 下里的代码我是动态加载到head头部的,只能在FireFox通过。不过实际情况你不必如此,你只要在服务端指定script的路径而不必动态加载。

<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">
    <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">
 
    //根据url上指定的语言进行解码
    var locale = window.location.search 
                 ? Ext.urlDecode(window.location.search.substring(1)).locale 
                 : '';
 
    // 将本地化的JS文件加入head元素内
    var head = Ext.fly(document.getElementsByTagName('head')[0]);
    if(locale) {
        Ext.DomHelper.append(head, {
             tag:'script'
            ,type:'text/javascript'
            ,src:'../ext/src/locale/ext-lang-' + locale + '.js'
        });
    }
 
    //预先定义的window继承类
    Ext.ns('Tutorial');
    Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
        initComponent:function() {
            Ext.apply(this, {
                 width:500
                ,id:'winid'
                ,height:300
                ,layout:'fit'
                ,border:false
                ,closable:false
                ,title:Ext.get('title').dom.innerHTML
                ,items:[{
                     xtype:'form'
                    ,frame:true
                    ,defaultType:'textfield'
                    ,items:[{
                          xtype:'combo'
                         ,fieldLabel:'Select Language'
                         ,name:'locale'
                         ,store:new Ext.data.SimpleStore({
                             id:0
                            ,fields:['file', 'locale']
                            ,data:[
                                 ['cs', 'Czech']
                                ,['', 'English']
                                ,['fr', 'French']
                                ,['de', 'German']
                                ,['gr', 'Greece']
                                ,['hu', 'Hungarian']
                                ,['it', 'Italian']
                                ,['ja', 'Japaneese']
                                ,['pl', 'Polish']
                                ,['pt', 'Portugal']
                                ,['ru', 'Russian']
                                ,['sk', 'Slovak']
                                ,['es', 'Spanish']
                                ,['sv_SE', 'Swedish']
                                ,['tr', 'Turkish']
                            ]
                         })
                        ,listeners:{
                            select:{fn:function(combo){
                                window.location.search = '?' 
                                    + Ext.urlEncode({locale:combo.getValue()})
                                ;
                            }}
                        }
                        ,mode:'local'
                        ,editable:false
                        ,forceSelection:true
                        ,valueField:'file'
                        ,displayField:'locale'
                        ,triggerAction:'all'
                        ,value:locale
                     },{
                         fieldLabel:'Text Field'
                        ,allowBlank:false
                    },{
                         xtype:'datefield'
                        ,fieldLabel:'Date Field'
                        ,allowBlank:false
                    }]
                }]
            }); // eo apply
            Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
        } // eo function initComponent
    }); // eo Tutorial.LocalizationWin
 
Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
Ext.onReady(function() {
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = 'side';
 
    // create example window
    var win = new Tutorial.LocalizationWin();
    win.show();
});
    </script>
    <title id="title">Localization Example</title>
</head>
<body>
</body>
</html>

现在完整的本地化工作是限于ComboBox、TextField和DateField这些Ext基础组件。试试在已翻译好的DataPicker组件中输入一些文字。

原理是??

原理是一改变cobmo box里面的"Select Language"就会包含(include)相应的Ext本地化文件(这里我使用了一些技巧性的做法,改变本地化文件的过程是用过客户端脚本完成的)

本地化文件的葫芦里卖的什么药?

首先要打开本地化文件来看看,读懂里面的源码后不但对Ext的理解有帮助而且对整个程序的本地化,也是有帮助的。我们以法语版的DatePicker为例子:

if(Ext.DatePicker){
   Ext.override(Ext.DatePicker, {
      todayText         : "Aujourd'hui",
      minText           : "Cette date est antérieure à la date minimum",
      maxText           : "Cette date est postérieure à la date maximum",
      disabledDaysText  : "",
      disabledDatesText : "",
      monthNames        : Date.monthNames,
      dayNames          : Date.dayNames,
      nextText          : 'Mois suivant (CTRL+Flèche droite)',
      prevText          : "Mois précédent (CTRL+Flèche gauche)",
      monthYearText     : "Choisissez un mois (CTRL+Flèche haut ou bas pour changer d'année.)",
      todayTip          : "{0} (Barre d'espace)",
      okText            : "&#160;OK&#160;",
      cancelText        : "Annuler",
      format            : "d/m/y",
      startDay          : 1
   });
}

通过观察,我们得知如果DataPicker对象存在(这是需要检测的,事因有些ext是你自己可制定的)就重写DataPicker的部分属性;更严格说,我们是把法语的文字替换掉英语的文字而已。Ext.override的作用是在DatePicker建立实例之前改变class的原型。

应用程序的本地化

我们对范例文件略加修改,把所有的静态文本变为类成员,修改过后看起来是这样的:

<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">
    <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../ext/ext-all-debug.js"></script>
 
    <!-- Ext localization javascript -->
    <script type="text/javascript" id="extlocale"></script>
 
    <!-- Locale and example extension javascript -->
    <script type="text/javascript">
 
    // decode language passed in url
    var locale = window.location.search 
                 ? Ext.urlDecode(window.location.search.substring(1)).locale 
                 : ''
    ;
 
    // append locale script to the head
    var head = Ext.fly(document.getElementsByTagName('head')[0]);
    if(locale) {
        Ext.fly('extlocale').set({src:'../ext/src/locale/ext-lang-' + locale + '.js'});
    }
 
    // create pre-configured example window extension class
    Ext.ns('Tutorial');
    Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
         titleText:'Localization Example'
        ,selectLangText:'Select Language'
        ,textFieldText:'Text Field'
        ,dateFieldText:'Date Field'
        ,initComponent:function() {
            Ext.apply(this, {
                 width:500
                ,id:'winid'
                ,height:300
                ,layout:'fit'
                ,border:false
                ,closable:false
                ,title:this.titleText
                ,items:[{
                     xtype:'form'
                    ,frame:true
                    ,defaultType:'textfield'
                    ,items:[{
                          xtype:'combo'
                         ,fieldLabel:this.selectLangText
                         ,name:'locale'
                         ,store:new Ext.data.SimpleStore({
                             id:0
                            ,fields:['file', 'locale']
                            ,data:[
                                 ['cs', 'Czech']
                                ,['', 'English']
                                ,['fr', 'French']
                                ,['de', 'German']
                                ,['gr', 'Greece']
                                ,['hu', 'Hungarian']
                                ,['it', 'Italian']
                                ,['ja', 'Japaneese']
                                ,['pl', 'Polish']
                                ,['pt', 'Portugal']
                                ,['ru', 'Russian']
                                ,['sk', 'Slovak']
                                ,['es', 'Spanish']
                                ,['sv_SE', 'Swedish']
                                ,['tr', 'Turkish']
                            ]
                         })
                        ,listeners:{
                            select:{fn:function(combo){
                                window.location.search = '?' 
                                    + Ext.urlEncode({locale:combo.getValue()})
                                ;
                            }}
                        }
                        ,mode:'local'
                        ,editable:false
                        ,forceSelection:true
                        ,valueField:'file'
                        ,displayField:'locale'
                        ,triggerAction:'all'
                        ,value:locale
                     },{
                         fieldLabel:this.textFieldText
                        ,allowBlank:false
                    },{
                         xtype:'datefield'
                        ,fieldLabel:this.dateFieldText
                        ,allowBlank:false
                    }]
                }]
            }); // eo apply
            Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
        } // eo function initComponent
    }); // eo Tutorial.LocalizationWin
    </script>
 
    <!-- Application localization javascript -->
    <script type="text/javascript" id="applocale"></script>
 
    <!-- Set src for application localization javascript -->
    <script>
    if(locale) {
        Ext.fly('applocale').set({src:'app-lang-' + locale + '.js'});
    }
    </script>
 
    <!-- Main application -->
    <script type="text/javascript">
    Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
    Ext.onReady(function() {
        Ext.QuickTips.init();
        Ext.form.Field.prototype.msgTarget = 'side';
 
        // create example window
        var win = new Tutorial.LocalizationWin();
        win.show();
    });
    </script>
    <title id="title">Localization Example</title>
</head>
<body>
</body>
</html>

最后一步,我们需要为特定的语种创建程序本地化的文件(翻译,语种)。这里是app-lang-sk.js文件因为我操的是斯洛伐克语的缘故。你可因应你需求的语种去设置(保存html的格式放到同一目录下或修改上面代码的目录):

/**
 * 斯洛伐克语版的教程之本地化文件
 */
if(Tutorial.LocalizationWin) {
    Ext.override(Tutorial.LocalizationWin, {
         titleText:'Príklad lokalizácie'
        ,selectLangText:'Zvoľ jazyk'
        ,textFieldText:'Textové pole'
        ,dateFieldText:'Dátumové pole'
    });
}

高级提示

请明确,要做Ext程序的本地化需要遵循哪些的原则。关键点在于将所有翻译文本作为公共类的成员出现,重写原先类的prototype的属性

Advanced developers will immediately feel some drawback of having, maintaining and deploying that many localization files especially if they already have a server with some translating infrastructure such as GNU gettext. For these users I would recommend to generate localization files on the fly by the server using gettext as backend.

这种做法最大的好处是可讲翻译文件集中在一块(*.po),客户端和服务端都可以使用。

如果本地化这主题反映还不错的话而读者又非常想进一步了解我会写进阶的Ext本地化。

Enjoy!

延伸阅读:

posted @ 2008-05-23 23:44 meetrice 阅读(591) 评论(0) 编辑
This is my first stab at a tutorial, so hopefully it works out! Thanks to crafter for his code examples in this thread: http://extjs.com/forum/showthread.php?t=26320


Contents

[hide]

Entry Point

Let's assume the entry point to your application is index.asp, and it is structured as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
	<head>
	<link rel="stylesheet" type="text/css" href="/igs/includes/ext/resources/css/ext-all.css">	
	<script type="text/javascript" src="/igs/includes/ext/adapter/ext/ext-base.js"></script>
	<script type="text/javascript" src="/igs/includes/ext/ext-all.js"></script>
	<script type="text/javascript" src="login.js"></script>	
	</head>
	<body></body>
</html>

Obviously, modify the paths to your EXT directory accordingly. See the source for Login.js below

Login.js

Next comes login.js. This guy handles all the heavy lifting, and for me, has all the pieces I was missing coming from a more traditional way of thinking about user authentication. It creates the form, renders it to a popup window, presents the window to the user, sends the submission via ajax, and handles the success and failure response depending on whether your user entered successful credentials.

Ext.onReady(function(){
    Ext.QuickTips.init();
 
    
// Create a variable to hold our EXT Form Panel. 
    // Assign various config options as seen.     
    var login = new Ext.FormPanel(
        labelWidth:
80,
        url:
'login.asp'
        frame:
true
        title:
'Please Login'
        width:
230
        padding:
200
        defaultType:
'textfield',
    monitorValid:
true,
 
    
// Specific attributes for the text fields for username / password. 
    // The "name" attribute defines the name of variables sent to the server.
        items:[
                fieldLabel:
'Username'
                name:
'loginUsername'
                allowBlank:
false 
            }
,
                fieldLabel:
'Password'
                name:
'loginPassword'
                inputType:
'password'
                allowBlank:
false 
            }
],
 
    
// All the magic happens after the user clicks the button     
        buttons:[
                text:
'Login',
                formBind: 
true,     
                
// Function that fires when user clicks the button 
                handler:function()
                    login.getForm().submit(

                        method:
'POST'
                        waitTitle:
'Connecting'
                        waitMsg:
'Sending data',
 
            
// Functions that fire (success or failure) when the server responds. 
            // The one that executes is determined by the 
            // response that comes from login.asp as seen below. The server would 
            // actually respond with valid JSON, 
            // something like: response.write "{ success: true}" or 
            // response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}" 
            // depending on the logic contained within your server script.
            // If a success occurs, the user is notified with an alert messagebox, 
            // and when they click "OK", they are redirected to whatever page
            // you define as redirect. 
 
                        success:
function()
                            Ext.Msg.alert(
'Status''Login Successful!'function(btn, text){
                   
if (btn == 'ok'){
                                
var redirect = 'test.asp'
                                window.location 
= redirect;
                                   }

                    }
);
                        }
,
 
            
// Failure function, see comment above re: success and failure. 
            // You can see here, if login fails, it throws a messagebox
            // at the user telling him / her as much.  
 
                        failure:
function(form, action)
                            
if(action.failureType == 'server')
                                obj 
= Ext.util.JSON.decode(action.response.responseText); 
                                Ext.Msg.alert(
'Login Failed!', obj.errors.reason); 
                            }
else
                                Ext.Msg.alert(
'Warning!''Authentication server is unreachable : ' + action.response.responseText); 
                            }
 
                            login.getForm().reset(); 
                        }
 
                    }
); 
                }
 
            }

    }
);
 
 
    
// This just creates a window to wrap the login form. 
    // The login object is passed to the items collection.       
    var win = new Ext.Window({
        layout:
'fit',
        width:
300,
        height:
150,
        closable: 
false,
        resizable: 
false,
        plain: 
true,
        items: [login]
    }
);
    win.show();
}
);

Login.asp

Here is the server processing for your login. I'm going to paste the following overly simplistic code to show the responses that go back, and ultimately determine which function in login.js fires (success or failure). However, this is where you would make the call to the database with the username/password variables, do your authentication, and then send either of these responses depending on whether or not what the user provided a valid set of credentials.

<%
 
if request.form("loginUsername") = "f" then
	response.write "{ success: true}"
else
	response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}"
end if
 
%>

Login.php

<?php
$loginUsername = isset($_POST["loginUsername"]) ? $_POST["loginUsername"] : "";
 
if($loginUsername == "f"){
    echo "{success: true}";
} else {
    echo "{success: false, errors: { reason: 'Login failed. Try again.' }}";
}
?>

Login.cfm

<cfsetting showdebugoutput="No">
<cfif form.loginUsername eq "f">
    <cfset result = "{success: true}">
<cfelse>
    <cfset result="{success: false, errors: { reason: 'Login failed. Try again.' }}">
</cfif>
<cfoutput>#result#</cfoutput>

Test.asp

You will notice a line in login.js that redirects to Test.asp if a successful login happens. This can obviously be whatever page your main application will be. In my situation, users can have any number of combinations of navigation options, so the next step would be to validate with whatever session management mecahanism you use, that the person accessing test.asp is authenticated to do so. Further, I would pull down whatever navigation options are assigned to that user and build my toolbar accordingly. Since I'm still trying to figure that part out, that will be another tutorial :)

Hopefully this is somewhat helpful and thanks again to crafter for most of the js code.

posted @ 2008-05-23 23:42 meetrice 阅读(476) 评论(0) 编辑

Tutorial:Writing a Big Application in Ext

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: This tutorial helps you to write a big application in Ext.
Author: Jozef Sakalos
Published: April 12, 2008
Ext Version: 2.0+
Languages: en.png English

Contents

[hide]

Preface

I have decided to write this article for those users of Ext 2.x that have already grown up from children's diapers of having one HTML page with embedded script that creates one simple window or form; for those who are already decided that Ext is the way; and for those who are fighting with too long files hardly to search in and feeling that their applications need a structure.

The number of approaches to a problem and the number of solutions to it is equal to the number of people that tackle it. The way I am going to describe in the following text is not the only one, and I do not want to say that either an application is going to be written my way or it is not good. Nothing like that.

What I do want to say is that this approach is workable, neatly structured, easily maintainable --- simply stated: It works!

What is "A Big Application"?

If you have a Viewport with BorderLayout, a grid and a form all in one file, it certainly is not the big application, right? If you have tens of windows each with a grid, form or border layout in it, in tens of files, it certainly is the big application, right?

(Germans have a very nice word: Jein which is combination of Ja = Yes and Nein = No.)

The answer to both above statements is Jein. When does the application become big, then? The answer is simple: It becomes big when you feel it is big. It is the point when you start to have troubles to orient yourself in a number of files or you have troubles to find a specific place in one file, when you cease to understand relations of components, etc. I am writing you here but imagine when a 2-3 grades less experienced programmer starts to have this feelings.

We can safely state that each application is big as also a small application deserves to be well written and it may likely become really big as we start to add new features, write new lines of code, new CSS rules, etc.

The best and the safest state of the mind at the start of a new application is: I'm starting the big application!

Files and Directories

These we need to organize first. There is always a DocumentRoot directory configured in Apache or another HTTP server, so all subdirectories I'll describe later are relative to it.

Recommended directory structure:

./css (optionally link)
./ext (link)
./img (link)
./js
index.html

Link in the above structure means a soft link pointing to a real directory where files are stored. The advantage is that when you, for example, download a new Ext version to a real directory, then you just change the link above to point there, and without changing a line in your application you can test if everything works also with this new version. If yes, keep it as it is; if no, just change the link back.

  • css will hold all your stylesheets. If you have global stylesheets with company colors or fonts you can create the css directory as a link too.
  • ext link you your Ext JS Library tree as described above
  • img link to your images. It can contain an icons subdirectory as well.
  • js will hold all JavaScript files the Application is composed of.
  • index.html HTML file that is an entry point of your application. You can name it as you want and you may need some more files, for example for a login process. Anyway, there is one application entry point/file.
  • optionally you can create a directory or a link for your server side part of the application (I have ./classes). You can name it as you wish but consistently for all applications you write (./server, ./php are some good examples)


index.html

Minimal index.html file content is:

<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>

Although you can do with the above file I would recommend to add a descriptive header to not only this file but to all files you create. Also an "End of file" marker has its value. See File Patterns for example of such headers.


js/application.js

We need a file where the onReady function will be placed; let's call it application.js. Its minimum content is:

// 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

Your header and footer may vary but sure you need to set Ext.BLANK_IMAGE_URL to point to your server. This is the path to a 1x1 px transparent image file that is used by Ext as an image placeholder, and if it points to an invalid location you can get various rendering problems such as missing combo trigger images, missing icons or similar.

You may also need to create a new global object variable for your application (here it is Application).

What you need for sure is Ext.onReady that is the main application entry point -- the place where you write your application.

css/application.css

You will put your css stylesheet, if any, into this file. If you need only a couple of rules it may seem as unnecessary to create a separate file for them, and it looks like a better idea to put them into <style> tags in the page head.

The reverse is true, remember you're writing a big application, so everything has to have its place. If you put styles in the page head sooner or later you will have to solve some rendering problems and you won't know where the styles are.

The wrong way

What does normally follow when we have all basics in, as we have at this point? Let's begin writing. So we sit down and we start to write:

var vp = new Ext.Viewport({
     layout:'border'
    ,items:[
        new Ext.grid.GridPanel({
            store:new Ext.data.Store({
                 proxy:new Ext.data.HttpProxy({ ...

Wait a minute. This way we will have 10,000 lines in our application.js very soon and that is what we want last. Obviously, some step is missing as if we're going to create such a big file why couldn't we write it in index.html in the first place?

The right way: Break it apart

Even the most complex whole consists of smaller systems which consist of smaller parts which consist of some elements. Your to-be-written big application is not an exception. Now it is the time to identify these parts, components and relationships between them.

So, sit down, think it over, draw a sketch, make a list, whatever, but the result has to be that you know the components --at least the most important ones-- your application will consist of.

Pre-configured classes

Now that you are done with application analysis and identifying its components you can start to write the first one. But how? The best approach is to write extension classes of Ext components that have all configuration options, otherwise passed as the configuration object, built-in. I call such extension pre-configured classes, as they rarely add much functionality to base Ext ones, but the main purpose of having them is to have them configured. For example, to have a "Personnel" grid with personnel specific column model, store, sorting options, editors, etc.

If we had such, our configuration of a Window could look like:

var win = new Ext.Window({
     title:'Personnel'
    ,widht:600
    ,height:400
    ,items:{xtype:'personnelgrid'}
});
win.show();


Writing a pre-configured class

Let's take an example to discuss:

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);

What are we doing here? We're extending Ext.grid.GridPanel creating a new class (extension) Application.PersonnelGrid, and we are registering it as a new xtype with name personnelgrid.

We are giving the general grid panel all the configuration options needed to become the specific personnel grid. From this point on we have a new component, a building block for our application that we can use everywhere (window, border panel region, standalone) where the list of personnel is needed. We can create it either as:

var pg = new Application.PersonnelGrid();

or using its xtype (lazy instantiation):

var win = new Ext.Window({
     items:{xtype:'personnelgrid'}
    ,....
});

Organizing pre-configured classes

The code above does not need to and should not run within the onReady function, because it has nothing to do with the DOM structure; it only creates a new JavaScript object. Therefore it can and it should be written in a separate file (js/Application.PersonnelGrid.js), and it can and must be included in the index.html header as:

<script type="text/javascript" src="js/Application.PersonnelGrid.js></script>

So far so good, we have almost everything in place and (almost) all we need to do more is to continue writing our pre-configured classes, put them into the ./js directory, include them in index.html and build our application from instances of them, as a puzzle is assembled from pieces.

Looks good, yeah?

Anyway, there is a bit more to it.

Inter-component communication

Imagine that we need a border layout with a link list in the west and a tab panel in the center region. Clicking a link in the west would create a new tab in the center. Now, where should we put the logic of it, event handler and creation routine? In the west, or in the center?

In neither of them. Why? If we have a pre-configured class that creates and displays the west link list and we put the above logic in it, it can no longer exist without the center region. We just cannot use it without the center, as then we have no component to create tabs in.

If we put it in the center, the result is the same: center cannot exist without west.

The only component that should be aware of the existence of both west and center panels is their container with the border layout, and this is the only right place where to put inter-component communication.

What should we do then? The container (with border layout) should listen to events fired by the west and it should create tabs in the center as responses to these clicks. An example of the component communication written this way can be found here: Saki's Ext Examples.

Production Systems

As we keep on writing our application we happen to have large number of included JavaScript files very soon (I have around 80 includes in one application at present and this number grows every day). This can degrade performance of a production system.

The best way to solve it is to concatenate all JavaScript files in the right order to create one big file, and to minify it with some of the JavaScript minifying or compression tools. Also, you do not need the debug version of the Ext library for production systems.

On a production system we would include:

  • ext-all.js
  • app-all.js and
  • application.js

For additional information about minimizing your source and creating combined build files, we have another tutorial that covers this topic in depth.

Conclusion

It's almost all there is to it... There are specific techniques for specific Ext classes, there is a lot of another server and client side know-how but the above is the overall concept.

Happy coding!

See also

posted @ 2008-05-23 23:40 meetrice 阅读(684) 评论(1) 编辑

Tutorial:Application Layout for Beginners (Chinese)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: 在本教程将助你合理地规划一个应用程序。
Author: Jozef Sakalos(译者:Frank Cheung)
Published: August 27, 2007
Ext Version: 1.1+ / 2.0+
Languages: en.png Englishcn.png Chinesebr.png Portuguese

kr.png Korean

Contents

[hide]

事前准备

本教程假设你已经安装好ExtJS库。安装的目录是extjs 并位于你程序的上一级目录。如果安装在其它地方你必须更改路径,更改示例文件中script标签的src的属性。

需要些什么?

除ExtJS库本身外,我们还需要两个文件:

  • applayout.html
  • applayout.js


先看看一份html文档,比较精简。并附有详细说明:

applayout.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">
    <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="applayout.js"></script>
    <!-- 本地化的脚本引用在这里 -->
    <script type="text/javascript">
        Ext.onReady(myNameSpace.app.init, myNameSpace.app);
    </script>
    <title>Application Layout Tutorial</title>
</head>
<body>
</body>
</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

/**
  * Application Layout
  * by Jozef Sakalos, aka Saki
  * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners_(Chinese)
  */
/**
------------------------------------------------
中文用户请注意:applayout.js 这个文件应该在编辑生成文件的同时强行定义为UTF-8编码才可以通过. 
------------------------------------------------
*/
// 填充图片的本地引用
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
 
// 创建命名空间
Ext.namespace('myNameSpace');
 
// 创建应用程序
myNameSpace.app = function() {
    // 元素还没创建,未能访问
 
    // 私有变量
 
    // 私有函数
 
    // 公共空间
    return {
        // 公共的属性,如,要转换的字符串
        // 公共方法
        init: function() {
            alert('应用程序初始化成功。');
        }
    };
}(); // 程序底部
 
// 文件底部

文件最开始的几行是注释,说明该文件的主要内容、作者、作者相关的资讯。没有任何注释的程序也可以正常的运行,————但请记住:每次写的程序要容易给人看得懂的 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加入下来代码:

/**
  * Application Layout
  * by Jozef Sakalos, aka Saki
  * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners_(Chinese)
  */
 
//  填充图片的本地引用
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
// 允许这个指南同时在Ext2.0 和1.1 上同时工作
Ext.Ext2 = (Ext.version && (Ext.version.indexOf("2") == 0));
 
// 创建命名空间
Ext.namespace('myNameSpace');
 
// 创建应用程序
myNameSpace.app = function() {
    // 元素还没创建,未能访问
 
    // 私有变量
    var btn1;
    var privVar1 = 11;
 
    // 私有函数
    var btn1Handler = function(button, event) {
        alert('privVar1=' + privVar1);
        alert('this.btn1Text=' + this.btn1Text);
    };
 
    // 公共空间
    return {
        // 公共的属性,如,要转译的字符串
        btn1Text: 'Button 1',
 
        // 公共方法
        init: function() {
            if (Ext.Ext2) {
                btn1 = new Ext.Button({
                    renderTo: 'btn1-ct',
                    text: this.btn1Text,
                    handler: btn1Handler
                });
            } else {
                btn1 = new Ext.Button('btn1-ct', {
                    text: this.btn1Text,
                    handler: btn1Handler
                });
            }
        }
    };
}(); //程序底部
 
// 文件底部

变量btn1privVar1私有的。 那意味着在程序外部他们是不能够被访问的,而且也不可见。私有函数btn1Handler也是同样道理。

另外一个方面,btn1Text是公共变量所以可以被程序外部访问或者是修改(我们稍后将会演示)。

函数init特权的,即是私有变量和公共变量两者都可以被它访问到。在本例中,公共变量this.btn1Text和私有函数btn1Handler都能够被特权函数init所访问。同时,相对外界来说,它也属于公共成员的一种。

Ok,运行看看。能看到左上角的按钮吗?很好,点击它。得到一个privVar1=11的警告。这说明私有函数能访问私有变量。

但是,在第二个alert中,this.btn1Text却是undefined,表示是未定义的,这不是我们期望的结果。原因是在handler内的this变量指向的是button而不是我们的myNameSpace.app .增加scope属性来指明thismyNameSpace.app

if (Ext.Ext2) {
    btn1 = new Ext.Button({
        renderTo: 'btn1-ct',
        text: this.btn1Text,
        handler: btn1Handler,
        scope:this
    });
} else {
    btn1 = new Ext.Button('btn1-ct', {
        text: this.btn1Text,
        handler: btn1Handler,
        scope:this
    });
}

刷新一下,可以了吧?

重写公共变量

applayout.js底部加入下列代码:

Ext.apply(myNameSpace.app, {
    btn1Text:'Taste 1'
});
 
// 文件底部

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


把文本都放到公共变量,以便于以后的国际化翻译工作,而不需要修改程序的内部代码。

当然你也可以将其它的值例如尺寸、样式、等等的总之是可自定义的选项都放到公共变量中。免于在数千行代码之中为查找某个颜色而费劲。

重写(Overriding)公共函数

接着更改一下代码,让它读起来是这样的:

Ext.apply(myNameSpace.app, {
      btn1Text:'Taste 1'
    , init: function() {
        try {
            btn1 = new Ext.Button('btn1-ct', {
                  text: this.btn1Text
                , handler: btn1Handler
                , scope: this
            });
        }
        catch(e) {
            alert('错误: "' + e.message + '" 发生在行: ' + e.lineNumber);
        }
    }
});
 
// end of file

我们这里将init重写了一篇,主要是在原来代码的基础上加入异常控制,以便能够捕获异常。试运行一下看还有没有其它的变化?

嗯 是的,出现了btn1Handler 未定义的错误。这是因为新的函数虽然尝试访问私有变量但它实际是不允许的。正如所见,原init是特权函数可访问私有空间,但新的init却不能。之所以不能访问私有空间,是因为:禁止外部代码No code from outside,哪怕是尝试重写特权方法。


参见

posted @ 2008-05-23 23:38 meetrice 阅读(208) 评论(0) 编辑

In this small tutorial, we'll try to build an Ext form that will submit in the tradional way, like all regular html forms

Introduction

As a programmer, you may know PHP (or ASP, or any other server-side language) and the tradional way of working with user-interfaces. You build forms in your server-side language, and output them in plain-text html to the end-user. You may use a templating engine, but in the end, you're sending nicely formatted html to the end-user.

With Ext, it's really easy to build nice-looking forms and interfaces, so you'd like to use that. But you also have a lot of code that already works, which you'd rather keep than converting all of it to handle JSON-formatted data etc.

At least, that was and is my current situation.

Getting Started: the HTML page

You've most probably already read how to include all required Ext-code in your page, but let me repeat that for you: (place this in the head-section of your html doc)

<title>A tradional form</title>
<!-- Include Ext and app-specific scripts: -->
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext/ext-all-debug.js"></script>
 
<!-- Include your own Javascript file here - adapt the filename to your filename-->
<script type="text/javascript" src="ext/mytestscript.js"></script>  
 
 
<!-- Include Ext stylesheets here: -->
<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css">

Next to that, your page certainly needs a place where we'll render the form. (put this in the body of your page)

<div id="mytradionalform"></div>

That's it, for you html code. You can put this in a regular html file (e.g. form.html), or you can output it via a server-side script. Doesn't matter.

The Javascript code

Next, we'll build the Javascript code. Best practice seems to be to put this in a separate file. I've called it "mytestscript.js" (see html above). Doesn't matter how you call it, just make sure to reference the correct file.

See the code below.

Ext.onReady(function(){
 
	var simple = new Ext.form.FormPanel({
 
 
        standardSubmit: true,
 
 
        frame:true,
        title: 'Register',
 
        width: 350,
        defaults: {width: 230},
        defaultType: 'textfield',
		items: [{
                fieldLabel: 'Username',
                name: 'username',
                allowBlank:false
            },
			{
                inputType: 'hidden',
                id: 'submitbutton',
                name: 'myhiddenbutton',
                value: 'hiddenvalue'
            }
 
        ],
        buttons: [{
            text: 'Submit',
            handler: function() {
		simple.getForm().getEl().dom.action = 'test.php';
	        simple.getForm().getEl().dom.method = 'POST';
                simple.getForm().submit();
            }
        }]
 
 
    });
 
 
 
    simple.render('mytradionalform');
 
 
 
});

Important part of this script are:

  • The "standardSubmit: true" line, which will make sure the form is submitted via the standard way
  • The handler for the submit button. At first I thought adding "standardSubmit: true" would be sufficient, but it's not.
  • simple.render() says where the form should be places. if you change the id of the <div> tag in your html, don't forget to change this name too
posted @ 2008-05-23 23:32 meetrice 阅读(1628) 评论(0) 编辑
posted @ 2008-05-23 23:30 meetrice 阅读(420) 评论(0) 编辑

Contents

[hide]

事前准备

学习本教程的最佳方法是随手准备好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"的作用域实际指向了window对象。不过多数情况中你不需要像这样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); }};

结果是什么?你声明了o1o2两个对象,分别都有一些属性和方法,但值不同。


接着试试:

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。

希望本文能帮助读者彻底理解作用域变量可见性的含义。

延伸阅读:

Retrieved from "http://extjs.com/learn/Tutorial:What_is_that_Scope_all_about_%28Chinese%29"

Contents

[hide]

引言

就像前文所述那样,firebug依然是配合本文验证概念的最方便工具。

嵌套的函数(作用域链)

当你进行函数的嵌套时,要注意实际上作用域链是发生变化的,这点可能看起来不太直观。你可把下面的代码置入firebug监视值的变化。

var testvar = 'window属性';
var o1 = {testvar:'1', fun:function(){alert('o1: '+this.testvar+'<<');}};
var o2 = {testvar:'2', fun:function(){alert('o2: '+this.testvar);}};
o1.fun();'1'
o2.fun();'2'
o1.fun.call(o2);'2'

这是本文的首个例子。

var testvar = 'window属性';
var o3 = {
   testvar:'3',
   testvar2:'3**',
   fun:function(){
      alert('o3: '+this.testvar);//'obj3'
      var inner = function(){
         alert('o3-inner: '+this.testvar);//'window属性'
         alert('o3-inner: '+this.testvar2);//undefined(未定义)
      };
      inner();
   }
};
o3.fun();

这里我们换了别的函数,这个函数与原先的函数几乎相似但区别是内部函数的写法。要注意的是内部函数运行时所在的作用域,和外部函数的作用域是不一样的。Ext可让你调用函数时指定函数的作用域,避免作用域的问题。

变量的声明

初始化变量时一定要加上“var”关键字,没有的话这就是一个全局变量。譬如,在下面的例子中,会有一个变量写在函数内部,然而你打算仅仅是声明局部的变量,但实际也可能出现覆盖全局变量的值的情形。在FIREBUG "DOM"的标签页中,你可通过检测“window”看到所有的全局变量。如果你发现有“k”或“x”变量那证明你把这个变量分配在一个不合适的作用域里面。见下例:

var i = 4;
var j = 5;
var k = 7;
var fn = function(){
   var i = 6;
   k = 8;//注意前面没有var 所以这句话的意思的把8赋予到变量k中去!
   alert(i);//6
   alert(j);//5
   alert(k+'-1');//8-1
   x = 1;//这句的作用有两种情况,创建全部变量x或覆盖(overwrite)全部变量x
};
fn();
alert(k+'-2');//8-2 (注意不是7-2)

与前面例子变化不大,另外注意的是函数内的k前面是没有var关键字的,所以这里不是声明局部变量,而是将某个值再次分配到k这个全局变量中。另外要注意的是,alert方法执行期间,参数i是当前能找到的局部变量,它的值是6,但参数j在当前作用域找不到,就沿着作用域链(scope chain)向上查找,一直找到全局变量的那个j为止。

在Ext中指定作用域

前面已提及,当调用函数时Ext能灵活处理作用域的问题。部分内容来自dj的帖子。

调用函数时,你可以把this想象为每个函数内的一个特殊(躲起来的)参数。无论什么时候,JavaScript都会把this放到function内部。它是基于一种非常简单的思想:如果函数直接是某个对象的成员,那么this的值就是这个对象。如果函数不是某个对象的成员那么this的值便设为某种全局对象(常见有,浏览器中的window对象)。下面的内部函数可以清晰的看出这种思想。

一个函数,若是分配到某个变量的,即不属于任何对象下的一员,那么this的参数就变为windows对象。下面是一个例子,可直接粘贴到Firebug的console:

var obj = {
	toString:function(){ return 'obj的范围内(作用域内)';}, //重写toString函数,方便执行console.log(this)时的输出
	func: function(){
		// 这里的函数直接从属与对象"object"
		console.log(this); 
		var innerFunc = function(){
			//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
			console.log(this); 
		};
		innerFunc();
	}
};
obj.func(); 
// 输出 "obj的范围内(作用域内)"
// 输出 "Window的一些相关内容..."

缺省下是这样调用一个参数的-但你也可以人为地改变this参数,只是语法上稍微不同。将最后一行的"obj.func();" 改为:

obj.func.call(window);
// 输出 "Window的一些相关内容..."
// 输出 "Window的一些相关内容..."

从上面的例子中可以发现,call实际上是另外一个函数(方法)。call 属于系统为obj.func内建的方法(根据JavaScript之特点可得知,函数是一种对象。)。

通过这样改变this指向的作用域,我们可以继续用一个例子来修正innerFunc中的this参数,——“不正确”的指向:

var obj = {
	toString:function(){ return 'obj的范围内(作用域内)';}, //重写toString函数,方便执行console.log(this)时的输出
	func: function(){
		// 这里的函数直接从属与对象"object"
		console.log(this); 
		var innerFunc = function(){
			//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
			console.log(this); 
		};
		innerFunc.call(this);
	}
};
obj.func(); 
// 输出 "obj的范围内(作用域内)"
// 输出 "obj的范围内(作用域内)"

Ext的作用域配置

可以看到,没有分配作用域的函数,它的this"指向的是浏览器的window对象(如事件句柄event handler等等),——除非我们改变this的指针。Ext的很多类中 scope是一个配置项(configuration)能够进行指针的绑定。相关的例子参考Ajax.request

Ext的createDelegate函数

*除了内建的call/apply方法,Ext还为我们提供-- 辅助方法createDelegate。 该函数的基本功能是绑定this指针但不立刻执行。传入一个参数,createDelegate方法会保证函数是运行在这个参数的作用域中。如:

var obj = {
	toString:function(){ return 'obj的范围内(作用域内)';}, //重写toString函数,方便执行console.log(this)时的输出
	func: function(){
		// 这里的函数直接从属与对象"object"
		console.log(this); 
		var innerFunc = function(){
			//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
			console.log(this); 
		};
		innerFunc = innerFunc.createDelegate(this); // 这里我们用委托的函数覆盖了原函数。
		innerFunc(); // 按照一般的写法调用函数
	}
};
obj.func(); 
// 输出 "obj的范围内(作用域内)"
// 输出 "obj的范围内(作用域内)"

这是一个小小的例子,其原理是非常基本基础的,希望能够好好消化。尽管如此,在现实工作中,我们还是容易感到迷惑,但基本上,如果能按照上面的理论知识去分析来龙去脉,万变还是不离其中的。

另外还有一样东西,看看下面的例子:

varsDs.load({callback: function(records){
  col_length = varsDs.getCount();//这里的varDs离开了作用域?
  //col_length = this.getCount();//这个this等于store吗?
  for (var x = 0; x < col_length; x++)
  {
  colarray[x] = varsDs.getAt(x).get('hex');
  }
}});

不过可以写得更清晰:

var obj = {
   callback: function(records){
      col_length = varsDs.getCount();//这里的varDs离开了作用域?
      //col_length = this.getCount();//这个this等于store吗?
      // ...
   }
};
varsDs.load(obj);

现在函数callback直接挂在obj上,因此this指针等于obj。

但是注意: 这样做没用的。为什么?因为你不知obj.callback最终执行时发生什么情形。试想一下Ext.data.Store的load方法(仿造的实现):

...
	load : function(config) {
		var o = {};
		o.callback = config.callback;
 
		  //进行加载
 
		o.callback();
	}
...

这个仿造的实现中,回调函数的作用域是私有变量“o”。 因为通常你无法得知函数是如何被调用的,如果不声明作用域,你很可能无法在回调函数中使用this参数。

Further reading:

posted @ 2008-05-23 23:25 meetrice 阅读(2264) 评论(2) 编辑


Summary: Playing With Ext The Easy Way (Chinese)
Author: Patrick Donelan (翻译:Cloudream)
Published: 2007-10-12
Ext Version: 2.0
Languages: en.png English de.png Deutschcn.png Chinese kr.png Koreanjp.png Japanese

Contents

[hide]

蹒跚学步

第一步 - 入门

想必您已经听说过 Ext、浏览了在线演示,并且尝试阅读API文档。不过,面对复杂的API文档,您却不如何下手?!

第二步 - 起步

通览过API文档,并且找到了所要立刻尝试的功能,面对混杂的网页源代码,如何开始一个简单的测试页面?那么……

不论您的目标是什么,您都可以依照本文快速的开始使用Ext。不,不用搭建服务器,您所需要的仅仅是Firefox浏览器和Firebug调试插件。如果还没有安装,那么现在就是一个好机会。


牛刀小试

  • 打开Ext API文档,您已经上路!
  • 单击 F12 打开 Firebug 控制台。
  • 如果您的 firebug 控制台处于单行模式(以 '>>>' 开头),那么请单击右下角的红色上箭头以开启多行编辑模式。
  • 输入以下代码,并敲击 Ctrl-Enter 来运行:
Ext.get(document.body).update('<div id="test"></div>');

上边这行代码的作用是将当前DOM body元素用一个ID为test的div元素替换。刚才那些API文档已经被删除,但 Ext 代码依旧生效,并且随时为您效劳。

现在,我们假设您希望简单的添加一个面板元素(Panel),但对Ext.Panel的API冗繁的说明无能为力。那么试着将这些代码添加到 firebug 的控制台中:

Ext.get(document.body).update('<div id="test"></div>');
new Ext.Panel({
	renderTo: 'test',
	width: '200px',
	title: 'My Title',
	html: 'My HTML content'
});

再次敲击 Ctrl-Enter 。嗨!您的面板元素已经诞生。

很好,不过如果修改一些选项呢?用下边的代码替换刚才的那些代码:

Ext.get(document.body).update('<div id="test"></div>');
new Ext.Panel({
	renderTo: 'test',
	width: '200px',
	title: 'My Title',
	html: 'My HTML content',
	collapsible: true
});

敲击 Ctrl-Enter 。怎么样,一个可以伸缩的面板就配置好了。(注意面板右上角的小图标)

每次敲击 Ctrl-Enter ,第一行代码都会移除现有的内容,这样您就可以有一个干净的调试环境。这是一个简单的小技巧,十分方便您尝试各种配置选项。

您可以为update()函数添加所需要的 HTML 代码,无论多少。然后编写或多或少的 Javascript 来探索 Ext API。

还等什么?现在就去亲自实践 Ext Api 吧。

posted @ 2008-05-23 23:22 meetrice 阅读(235) 评论(0) 编辑
posted @ 2008-05-23 23:20 meetrice 阅读(716) 评论(0) 编辑
 Ext 2.0 Tutorials

All tutorials in this section were written for Ext 2.0, or can be used with any version of Ext. Looking for 1.x tutorials?


Getting Started

Application Design

DomQuery

Events

Drag & Drop

Tabs & Layouts

Tree

Grid

Advanced / Combination

Platform-Specific


 

Editing Category:Chinese

From Learn About the Ext JavaScript Library

Jump to: navigation, search

You've followed a link to a page that doesn't exist yet. To create the page, start typing in the box below (see the help page for more info). If you are here by mistake, just click your browser's back button.

posted @ 2008-05-23 23:18 meetrice 阅读(413) 评论(0) 编辑

本教程适用于Ext 2.0的版本,而版本1.x仍可找到。

无论你是Ext库的新手,抑或是想了解Ext的人,本篇文章的内容都适合你。本文将简单地介绍Ext的几个基本概念,和如何快速地做出一个动态的页面并运行起来,假设读者已具备了一些JavaScript经验和简单了解HTML的文档对象模型(document object model ,DOM)。

下载Ext

如果你未曾下载过,那应从官方网站那里下载最新版本的Ext http://extjs.com/downloads

因应各种的下载需求,有几种不同的可选项。通常地,最稳定的版本,是较多人的选择。下载解包后,那个example文件夹便是一个探索Ext的好地方!

开始!

下载示例文件


我们将讲讲怎么使用Ext,来完成一些JavaScript常见的任务。如果你想自己试试,就应该先下IntroToExt2.zip ,用来构建已下面的Ext代码。

Zip包里有三个文件:ExtStart.html, ExtStart.jsExtStart.css。解包这三个文件到Ext的安装目录中(例如,Ext是在“C:\code\Ext\v2.0”中,那应该在"v2.0"里面新建目录“tutorial”。双击ExtStart.htm,接着你的浏览器打开启动页面,应该会有一条消息告诉你配置已完毕。如果出现了Javascript错误,请按照页面上的指引操作。

现在在你常用的IDE中或文本编辑器中,打开ExtStart.js看看。

Ext.onReady(function() {
	alert("Congratulations!  You have Ext configured correctly!");
});

Ext.onReady可能是你接触的第一个也可能是在每个页面都要使用的方法。这个方法会在DOM加载全部完毕后,保证页面内的所有元素能被Script引用(reference)之后调用。你可删除alert()那行,加入一些实际用途的代码试试。

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 包含一个ID为“myDiv”的 div,然后,在ExtStart.js中加入下列语句): The corresponding code to get an Ext Element by ID looks like this (the starter page ExtStart.html contains a div with the id "myDiv," so go ahead and add this code to ExtStart.js):

Ext.onReady(function() {
	var myDiv = Ext.get('myDiv');
});

再回头看看Element对象,发现什么有趣的东东呢?

  • Element包含了常见的DOM方法和属性,提供一个快捷的、统一的、跨浏览器的接口(若使用Element.dom的话,就可以直接访问底层DOM的节点。);
  • Element.get()方法提供内置缓存(Cache),多次访问同一对象效率上有极大优势;
  • 内置常用的DOM节点的动作,并且是跨浏览器的定位的位置、大小、动画、拖放等等(添加/移除 CSS 类, 添加/移除事件处理程序, 定位, 改变大小, 动画, 拖放)。

这意味着你可用少量的代码来做各种各样的事情,这里仅仅是一个简单的例子(完整的列表在Element API 文档中)。

继续在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包含若干段落(<p>标签),没有一个是有ID的,而你想轻松地通过一次操作马上获取每一段,全体执行它们的动作,可以这样做:

// 每段高亮显示
Ext.select('p').highlight();

Element.select在这个例子中的方便性显露无疑。它返回一个复合元素,能通过元素接口(Element interface)访问每个元素。这样做的好处是可不用循环和不分别访问每一个元素。

DomQuery的选取参数可以是一段较长的数组,其中包括W3C CSS3 Dom选取器、基本XPatch、HTML属性和更多,请参阅DomQuery API文档以了解这功能强大的库个中细节。

响应事件

到这范例为止,我们所写的代码都是放在onReady中,即当页面加载后总会立即执行,功能较单一——这样的话,你便知道,如何响应某个动作或事件来执行你希望做的事情,做法是,先分配一个function,再定义一个event handler事件处理器来响应。我们由这个简单的范例开始,打开ExtStart.js,编辑下列的代码:

Ext.onReady(function() {
    Ext.get('myButton').on('click', function(){
        alert("你单击了按钮");
    });
});

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

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

Ext.onReady(function() {
	Ext.select('p').on('click', function() {
		alert("你单击了一段落;");
	});
});

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

Ext.onReady(function() {
	var paragraphClicked = function() {
		alert("你单击了一段落;");
	}
	Ext.select('p').on('click', paragraphClicked);
});

到目前为止,我们已经知道如何执行某个动作。但当事件触发时,我们如何得知这个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();
	}
	Ext.select('p').on('click', paragraphClicked);
});

注意得到的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',
	msg: paragraph.dom.innerHTML,
	width:400,
	buttons: Ext.MessageBox.OK,
	animEl: paragraph
});

这里有些新的概念需要讨论一下。在第一行中我们创建了一个局部变量(Local Variable)来保存某个元素的引用,即被单击的那个DOM节点(本例中,DOM节点指的是段落paragrah,事因我们已经定义该事件与<p>标签发生关联的了)。为什么要这样做呢?嗯...观察上面的代码,我们需要引用同一元素来高亮显示,在MessageBox中也是引用同一元素作为参数使用。
一般来说,多次重复使用同一值(Value)或对象,是一个不好的方式,所以,作为一个具备良好OO思维的开发者,应该是将其分配到一个局部变量中,反复使用这变量!

现在,为了我们接下来阐述新概念的演示,请观察MessageBox的调用。乍一看,这像一连串的参数传入到方法中,但仔细看,这是一个非常特别的语法。实际上,传入到MessageBox.show的只有一个参数:一个Object literal(对象字面化),包含一组属性和属性值。在Javascript中,对象字面化是动态的,你可在任何时候用{和}创建一个典型的对象(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'],
		['Ext',83.81,0.28,0.34,'9/12 12:00am'],
		['Google',71.72,0.02,0.03,'10/1 12:00am'],
		['Microsoft',52.55,0.01,0.02,'7/4 12:00am'],
		['Yahoo!',29.01,0.42,1.47,'5/22 12:00am']
	];
 
	var myReader = new Ext.data.ArrayReader({}, [
		{name: 'company'},
		{name: 'price', type: 'float'},
		{name: 'change', type: 'float'},
		{name: 'pctChange', type: 'float'},
		{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
	]);
 
	var grid = new Ext.grid.GridPanel({
		store: new Ext.data.Store({
			data: myData,
			reader: myReader
		}),
		columns: [
			{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'}
		],
		viewConfig: {
			forceFit: true
		},
		renderTo: 'content',
		title: 'My First Grid',
		width: 500,
		frame: true
	});
 
	grid.getSelectionModel().selectFirstRow();
});

这看上去很复杂,但实际上加起来,只有四行代码(不包含测试数据的代码)。

  • 第一行创建数组并作为数据源。实际案例中,你很可能从数据库、或者WebService那里得到动态的数据。
  • 接着,我们创建并加载data store, data store将会告诉Ext的底层库接手处理和格式化这些数据。不同的数据类型须在类Reader中指明。
  • 接着,我们创建一个Grid的组件,传入各种的配置值,有:
    • 新的data store, 配置好测试数据和reader
    • 列模型column model定义了 列columns的配置
    • 其他的选择指定了Grid所需的功能
  • 最后,通过SelectionModel告诉Grid高亮显示第一行。

不是太困难吧?如果一切顺利,完成之后你会看到像这样的:

Image:IntroToExt2_grid.gif

当然,你现在还未掌握这段代码的某些细节,但先不要紧,这个例子的目的是告诉你,只要学习了少量的几行代码,创建一个富界面的多功能的UI组件是可能的。更多的grid细节读者可作为一种练习去学习。这儿有许多学习Grid的资源,Ext Grid教程、Grid交互演示交和Grid API文档

还有更多的..

这只是其中一部分。还有一打的UI Widgets可以供调用,如 layouts, tabs, menus, toolbars, dialogs, tree view等等。请探索 范例演示

使用Ajax

在弄好一些页面后,你已经懂得在页面和脚本之间的交互(interact)原理。接下来,你应该掌握的是,怎样与远程服务器(remote server)交换数据,常见的是从数据库加载数据(load)或是保存数据(save)到数据库中。通过JavaScript异步无刷新交换数据的这种方式,就是所谓的Ajax。Ext内建卓越的Ajax支持,例如,一个普遍的用户操作就是,异步发送一些东西到服务器,然后,UI元素根据回应(Response)作出更新。这是一个包含text input的表单,一个div用于显示消息(注意,你可以在ExtStart.html中加入下列代码,但这必须要访问服务器):

<div id="msg"></div>
<div>
    Name: <input type="text" id="name" />
    <input type="button" id="okButton" value="OK" />
</div>
<div id="msg"></div>

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


Ext.onReady(function(){
	Ext.get('okButton').on('click', function(){
		var msg = Ext.get('msg');
		msg.load({
			url: 'ajax-example.php', // <-- 按实际改动
			params: 'name=' + Ext.get('name').dom.value,
			text: 'Updating...'
		});
		msg.show();
	});
});

注意: 这个例子需要web server才可运行。 浏览器的URL地址不应是以file://开头,而是http://开头,否则的话Ajax的数据交互将不会工作。Localhost就可以工作得很好,但必须是通过http的。

这种模式看起来已经比较熟悉了吧!先获取按钮元素,加入一个匿名函数监听单击。在事件处理器中(event handler),我们使用一个负责处理Ajax请求、接受响应(Response)和更新另一个元素的Ext内建类,称作UpdateManagerUpdater。UpdateManager可以直接使用,或者和我们现在的做法一样,通过Element的load方法来引用(本例中该元素是id为“msg“的div)。当使用Element.load方法,请求(request)会在加工处理后发送,等待服务器的响应(Response),来自动替换元素的innerHTML。简单传入服务器url地址,加上字符串参数,便可以处理这个请求(本例中,参数值来自“name”元素的value),而text值是请求发送时提示的文本,完毕后显示那个msg的div(因为开始时默认隐藏)。当然,和大多数Ext组件一样,Ext.Ajax 有许多的参数可选,不同的Ajax请求有不同的方案。而这里仅演示最简单的那种。


最后一个关于Ajax隐晦的地方就是,服务器实际处理请求和返回(Resposne)是具体过程。这个过程会是一个服务端页面,一个Servlet,一个Http调度过程,一个WebService,甚至是Perl或CGI脚本,即不指定一个服务器都可以处理的http请求。让人无法预料的是,服务器返回什么是服务器的事情,无法给一个标准的例子来覆盖阐述所有的可能性。。

下面的例子是一些常见的语言以方便开始测试(这段代码输出刚才我们传入'name'的那个值到客户端,即发送什么,返回什么,然后在我们刚才写的'msg' div中加入该文本)。PHP的已经包含在下载文件中,文件名为'ajax-example.php',可换成你自己服务端的代码:

Plain PHP

<?php if(isset($_POST['name'])) {
		echo 'From Server: '.$_POST['name'];
	}
?>

CakePHP

<?php if(isset($this->data['name'])) {
		$this->flash('From Server: '.$this->data['name']);
	}
?>

Django

from django.http import HttpResponse
 
def ajax_request(request):
    return HttpResponse('From Server: %s' % request.POST.get('name', 'nada'))

Perl

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
 
my $Query = new CGI;
 
print $Query->header();
print "Hello from : ".$Query->param('name');
 
exit;

ASP.Net

protected void Page_Load(object sender, EventArgs e)
{
	if (Request.Form["name"] != null)
	{
		Response.Write("From Server: " + Request.Form["name"]);
		Response.End();
	}
}

ColdFusion

<cfif StructKeyExists(form, "name")>
    <cfoutput>From Server: #form.name#</cfoutput>
</cfif>

JSP

From Server: ${param.name}

使用Ajax的真正挑战,是需要进行适当的手工编码,并相应格式化为服务端可用接受的数据结构。有几种格式供人们选择(最常用为JSON/XML)。 Ext没有跟任何服务器语言有独家联系,因此其它特定语言的库亦可用于Ext处理Ajax服务。只要页面接受到结果是EXT能处理的数据格式,Ext绝不会干涉服务器其他的事情!推荐参阅我们提供的各个平台资源以了解服务端框架的更多资讯和辅助。

下一步是?

现在你已经一睹Ext其芳容,知道她大概能做些什么了。下面的资源有助您进一步深入了解:

posted @ 2008-05-23 23:16 meetrice 阅读(442) 评论(0) 编辑

    在html中,任何一个元素都有三个表示位置和大小的对象:client,offset和scroll,每个对象都有相应的height,width,top,left属性,那么这些究竟有什么区别呢?
    client属性是指一个元素直接可以看得到不包括边框的区域,所谓的直接可以看得到不包括边框是这样的概念:不包括滚动条占据的空间(实际上,如果出现了滚动条,元素的高度不会发生变化,clientHeight则会自动减少滚动条需要占据的17个像素的高度),不包括滚动条隐藏的区域、不包括边(border)。因此,clientHeight就是这个区域的高度,而clientTop实际上就是border的高度;
    offset属性是指一个元素直接可以看得到包括边框的区域,所谓的直接可以看得到包括边框是这样的概念:不包括滚动条隐藏的区域、包括边(border)的宽度。因此,offsetHeight就是这个区域的高度,而clientTop实际上是这个区域到它的父容器的距离;
    scroll高度和元素的边框没有关系,它是实际上元素的高度,因此,如果出现了滚动条,scrollHeight可能会大于offset或client的高度。scrollTop则是元素的实际的顶部和可见的顶部这件的距离。

posted @ 2008-05-23 22:47 meetrice 阅读(1111) 评论(2) 编辑
Oracle的sql*plus是与oracle进行交互的客户端工具。在sql*plus中,可以运行sql*plus命令与sql*plus语句。
我们通常所说的DML、DDL、DCL语句都是sql*plus语句,它们执行完后,都可以保存在一个被称为sql buffer的内存区域中,并且只能保存一条最近执行的sql语句,我们可以对保存在sql buffer中的sql 语句进行修改,然后再次执行,sql*plus一般都与数据库打交道。
除了sql*plus语句,在sql*plus中执行的其它语句我们称之为sql*plus命令。它们执行完后,不保存在sql buffer的内存区域中,它们一般用来对输出的结果进行格式化显示,以便于制作报表。
下面就介绍一下一些常用的sql*plus命令:

1. 执行一个SQL脚本文件
SQL>start file_name
SQL>@ file_name
我们可以将多条sql语句保存在一个文本文件中,这样当要执行这个文件中的所有的sql语句时,用上面的任一命令即可,这类似于dos中的批处理。

@与@@的区别是什么?
@等于start命令,用来运行一个sql脚本文件。
@命令调用当前目录下的,或指定全路径,或可以通过SQLPATH环境变量搜寻到的脚本文件。该命令使用是一般要指定要执行的文件的全路径,否则从缺省路径(可用SQLPATH变量指定)下读取指定的文件。
@@用在sql脚本文件中,用来说明用@@执行的sql脚本文件与@@所在的文件在同一目录下,而不用指定要执行sql脚本文件的全路径,也不是从SQLPATH环境变量指定的路径中寻找sql脚本文件,该命令一般用在脚本文件中。
如:在c:\temp目录下有文件start.sql和nest_start.sql,start.sql脚本文件的内容为:
@@nest_start.sql - - 相当于@ c:\temp\nest_start.sql
则我们在sql*plus中,这样执行:
SQL> @ c:\temp\start.sql


2. 对当前的输入进行编辑
SQL>edit

3. 重新运行上一次运行的sql语句
SQL>/

4. 将显示的内容输出到指定文件
SQL> SPOOL file_name
在屏幕上的所有内容都包含在该文件中,包括你输入的sql语句。

5. 关闭spool输出
SQL> SPOOL OFF
只有关闭spool输出,才会在输出文件中看到输出的内容。

6.显示一个表的结构
SQL> desc table_name

7. COL命令:
主要格式化列的显示形式。
该命令有许多选项,具体如下:
COL[UMN] [{ column|expr} [ option ...]]
Option选项可以是如下的子句:
ALI[AS] alias
CLE[AR]
FOLD_A[FTER]
FOLD_B[EFORE]
FOR[MAT] format
HEA[DING] text
JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
LIKE { expr|alias}
NEWL[INE]
NEW_V[ALUE] variable
NOPRI[NT]|PRI[NT]
NUL[L] text
OLD_V[ALUE] variable
ON|OFF
WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]

1). 改变缺省的列标题
COLUMN column_name HEADING column_heading
For example:
Sql>select * from dept;
DEPTNO DNAME LOC
---------- ---------------------------- ---------
10 ACCOUNTING NEW YORK
sql>col LOC heading location
sql>select * from dept;
DEPTNO DNAME location
--------- ---------------------------- -----------
10 ACCOUNTING NEW YORK

2). 将列名ENAME改为新列名EMPLOYEE NAME并将新列名放在两行上:
Sql>select * from emp
Department name Salary
---------- ---------- ----------
10 aaa 11
SQL> COLUMN ENAME HEADING ’Employee|Name’
Sql>select * from emp
Employee
Department name Salary
---------- ---------- ----------
10 aaa 11
note: the col heading turn into two lines from one line.

3). 改变列的显示长度:
FOR[MAT] format
Sql>select empno,ename,job from emp;
EMPNO ENAME JOB
---------- ---------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
Sql> col ename format a40
EMPNO ENAME JOB
---------- ---------------------------------------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN

4). 设置列标题的对齐方式
JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
SQL> col ename justify center
SQL> /
EMPNO ENAME JOB
---------- ---------------------------------------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
对于NUMBER型的列,列标题缺省在右边,其它类型的列标题缺省在左边

5). 不让一个列显示在屏幕上
NOPRI[NT]|PRI[NT]
SQL> col job noprint
SQL> /
EMPNO ENAME
---------- ----------------------------------------
7369 SMITH
7499 ALLEN
7521 WARD

6). 格式化NUMBER类型列的显示:
SQL> COLUMN SAL FORMAT $99,990
SQL> /
Employee
Department Name Salary Commission
---------- ---------- --------- ----------
30 ALLEN $1,600 300

7). 显示列值时,如果列值为NULL值,用text值代替NULL值
COMM NUL[L] text
SQL>COL COMM NUL[L] text

8). 设置一个列的回绕方式
WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]
COL1
--------------------
HOW ARE YOU?

SQL>COL COL1 FORMAT A5
SQL>COL COL1 WRAPPED
COL1
-----
HOW A
RE YO
U?

SQL> COL COL1 WORD_WRAPPED
COL1
-----
HOW
ARE
YOU?

SQL> COL COL1 WORD_WRAPPED
COL1
-----
HOW A

9). 显示列的当前的显示属性值
SQL> COLUMN column_name

10). 将所有列的显示属性设为缺省值
SQL> CLEAR COLUMNS

8. 屏蔽掉一个列中显示的相同的值
BREAK ON break_column
SQL> BREAK ON DEPTNO
SQL> SELECT DEPTNO, ENAME, SAL
FROM EMP
WHERE SAL < 2500
ORDER BY DEPTNO;
DEPTNO ENAME SAL
---------- ----------- ---------
10 CLARK 2450
MILLER 1300
20 SMITH 800
ADAMS 1100

9. 在上面屏蔽掉一个列中显示的相同的值的显示中,每当列值变化时在值变化之前插入n个空行。
BREAK ON break_column SKIP n

SQL> BREAK ON DEPTNO SKIP 1
SQL> /
DEPTNO ENAME SAL
---------- ----------- ---------
10 CLARK 2450
MILLER 1300

20 SMITH 800
ADAMS 1100

10. 显示对BREAK的设置
SQL> BREAK

11. 删除6、7的设置
SQL> CLEAR BREAKS

12. Set 命令:
该命令包含许多子命令:
SET system_variable value
system_variable value 可以是如下的子句之一:
APPI[NFO]{ON|OFF|text}
ARRAY[SIZE] {15|n}
AUTO[COMMIT]{ON|OFF|IMM[EDIATE]|n}
AUTOP[RINT] {ON|OFF}
AUTORECOVERY [ON|OFF]
AUTOT[RACE] {ON|OFF|TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
BLO[CKTERMINATOR] {.|c}
CMDS[EP] {;|c|ON|OFF}
COLSEP {_|text}
COM[PATIBILITY]{V7|V8|NATIVE}
CON[CAT] {.|c|ON|OFF}
COPYC[OMMIT] {0|n}
COPYTYPECHECK {ON|OFF}
DEF[INE] {&|c|ON|OFF}
DESCRIBE [DEPTH {1|n|ALL}][LINENUM {ON|OFF}][INDENT {ON|OFF}]
ECHO {ON|OFF}
EDITF[ILE] file_name[.ext]
EMB[EDDED] {ON|OFF}
ESC[APE] {\|c|ON|OFF}
FEED[BACK] {6|n|ON|OFF}
FLAGGER {OFF|ENTRY |INTERMED[IATE]|FULL}
FLU[SH] {ON|OFF}
HEA[DING] {ON|OFF}
HEADS[EP] {||c|ON|OFF}
INSTANCE [instance_path|LOCAL]
LIN[ESIZE] {80|n}
LOBOF[FSET] {n|1}
LOGSOURCE [pathname]
LONG {80|n}
LONGC[HUNKSIZE] {80|n}
MARK[UP] HTML [ON|OFF] [HEAD text] [BODY text] [ENTMAP {ON|OFF}] [SPOOL
{ON|OFF}] [PRE[FORMAT] {ON|OFF}]
NEWP[AGE] {1|n|NONE}
NULL text
NUMF[ORMAT] format
NUM[WIDTH] {10|n}
PAGES[IZE] {24|n}
PAU[SE] {ON|OFF|text}
RECSEP {WR[APPED]|EA[CH]|OFF}
RECSEPCHAR {_|c}
SERVEROUT[PUT] {ON|OFF} [SIZE n] [FOR[MAT] {WRA[PPED]|WOR[D_
WRAPPED]|TRU[NCATED]}]
SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]}
SHOW[MODE] {ON|OFF}
SQLBL[ANKLINES] {ON|OFF}
SQLC[ASE] {MIX[ED]|LO[WER]|UP[PER]}
SQLCO[NTINUE] {> |text}
SQLN[UMBER] {ON|OFF}
SQLPRE[FIX] {#|c}
SQLP[ROMPT] {SQL>|text}
SQLT[ERMINATOR] {;|c|ON|OFF}
SUF[FIX] {SQL|text}
TAB {ON|OFF}
TERM[OUT] {ON|OFF}
TI[ME] {ON|OFF}
TIMI[NG] {ON|OFF}
TRIM[OUT] {ON|OFF}
TRIMS[POOL] {ON|OFF}
UND[ERLINE] {-|c|ON|OFF}
VER[IFY] {ON|OFF}
WRA[P] {ON|OFF}

1). 设置当前session是否对修改的数据进行自动提交
SQL>SET AUTO[COMMIT] {ON|OFF|IMM[EDIATE]| n}

2).在用start命令执行一个sql脚本时,是否显示脚本中正在执行的SQL语句
SQL> SET ECHO {ON|OFF}

3).是否显示当前sql语句查询或修改的行数
SQL> SET FEED[BACK] {6|n|ON|OFF}
默认只有结果大于6行时才显示结果的行数。如果set feedback 1 ,则不管查询到多少行都返回。当为off 时,一律不显示查询的行数

4).是否显示列标题
SQL> SET HEA[DING] {ON|OFF}
当set heading off 时,在每页的上面不显示列标题,而是以空白行代替

5).设置一行可以容纳的字符数
SQL> SET LIN[ESIZE] {80|n}
如果一行的输出内容大于设置的一行可容纳的字符数,则折行显示。

6).设置页与页之间的分隔
SQL> SET NEWP[AGE] {1|n|NONE}
当set newpage 0 时,会在每页的开头有一个小的黑方框。
当set newpage n 时,会在页和页之间隔着n个空行。
当set newpage none 时,会在页和页之间没有任何间隔。

7).显示时,用text值代替NULL值
SQL> SET NULL text

8).设置一页有多少行数
SQL> SET PAGES[IZE] {24|n}
如果设为0,则所有的输出内容为一页并且不显示列标题

9).是否显示用DBMS_OUTPUT.PUT_LINE包进行输出的信息。
SQL> SET SERVEROUT[PUT] {ON|OFF}
在编写存储过程时,我们有时会用dbms_output.put_line将必要的信息输出,以便对存储过程进行调试,只有将serveroutput变量设为on后,信息才能显示在屏幕上。

10).当SQL语句的长度大于LINESIZE时,是否在显示时截取SQL语句。
SQL> SET WRA[P] {ON|OFF}
当输出的行的长度大于设置的行的长度时(用set linesize n命令设置),当set wrap on时,输出行的多于的字符会另起一行显示,否则,会将输出行的多于字符切除,不予显示。

11).是否在屏幕上显示输出的内容,主要用与SPOOL结合使用。
SQL> SET TERM[OUT] {ON|OFF}
在用spool命令将一个大表中的内容输出到一个文件中时,将内容输出在屏幕上会耗费大量的时间,设置set termspool off后,则输出的内容只会保存在输出文件中,不会显示在屏幕上,极大的提高了spool的速度。

12).将SPOOL输出中每行后面多余的空格去掉
SQL> SET TRIMS[OUT] {ON|OFF}

13)显示每个sql语句花费的执行时间
set TIMING {ON|OFF}

14). 遇到空行时不认为语句已经结束,从后续行接着读入。
SET SQLBLANKLINES ON
Sql*plus中, 不允许sql语句中间有空行, 这在从其它地方拷贝脚本到sql*plus中执行时很麻烦. 比如下面的脚本:
select deptno, empno, ename
from emp

where empno = '7788';
如果拷贝到sql*plus中执行, 就会出现错误。这个命令可以解决该问题

15).设置DBMS_OUTPUT的输出
SET SERVEROUTPUT ON BUFFER 20000
用dbms_output.put_line('strin_content');可以在存储过程中输出信息,对存储过程进行调试
如果想让dbms_output.put_line(' abc');的输出显示为:
SQL> abc,而不是SQL>abc,则在SET SERVEROUTPUT ON后加format wrapped参数。

16). 输出的数据为html格式
set markup html
在8.1.7版本(也许是816? 不太确定)以后, sql*plus中有一个set markup html的命令, 可以将sql*plus的输出以html格式展现.
注意其中的spool on, 当在屏幕上输出的时候, 我们看不出与不加spool on有什么区别, 但是当我们使用spool filename 输出到文件的时候, 会看到spool文件中出现了等tag.


14.修改sql buffer中的当前行中,第一个出现的字符串
C[HANGE] /old_value/new_value
SQL> l
1* select * from dept
SQL> c/dept/emp
1* select * from emp

15.编辑sql buffer中的sql语句
EDI[T]

16.显示sql buffer中的sql语句,list n显示sql buffer中的第n行,并使第n行成为当前行
L[IST] [n]

17.在sql buffer的当前行下面加一行或多行
I[NPUT]

18.将指定的文本加到sql buffer的当前行后面
A[PPEND]
SQL> select deptno,
2 dname
3 from dept;
DEPTNO DNAME
---------- --------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS

SQL> L 2
2* dname
SQL> a ,loc
2* dname,loc
SQL> L
1 select deptno,
2 dname,loc
3* from dept
SQL> /

DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

19.将sql buffer中的sql语句保存到一个文件中
SAVE file_name

20.将一个文件中的sql语句导入到sql buffer中
GET file_name

21.再次执行刚才已经执行的sql语句
RUN
or
/

22.执行一个存储过程
EXECUTE procedure_name

23.在sql*plus中连接到指定的数据库
CONNECT user_name/passwd@db_alias

24.设置每个报表的顶部标题
TTITLE

25.设置每个报表的尾部标题
BTITLE

26.写一个注释
REMARK [text]

27.将指定的信息或一个空行输出到屏幕上
PROMPT [text]

28.将执行的过程暂停,等待用户响应后继续执行
PAUSE [text]

Sql>PAUSE Adjust paper and press RETURN to continue.

29.将一个数据库中的一些数据拷贝到另外一个数据库(如将一个表的数据拷贝到另一个数据库)
COPY {FROM database | TO database | FROM database TO database}
{APPEND|CREATE|INSERT|REPLACE} destination_table
[(column, column, column, ...)] USING query

sql>COPY FROM SCOTT/TIGER@HQ TO JOHN/CHROME@WEST
create emp_temp
USING SELECT * FROM EMP

30.不退出sql*plus,在sql*plus中执行一个操作系统命令:
HOST

Sql> host hostname
该命令在windows下可能被支持。

31.在sql*plus中,切换到操作系统命令提示符下,运行操作系统命令后,可以再次切换回sql*plus:
!

sql>!
$hostname
$exit
sql>

该命令在windows下不被支持。

32.显示sql*plus命令的帮助
HELP
如何安装帮助文件:
Sql>@ ?\sqlplus\admin\help\hlpbld.sql ?\sqlplus\admin\help\helpus.sql
Sql>help index

33.显示sql*plus系统变量的值或sql*plus环境变量的值
Syntax
SHO[W] option
where option represents one of the following terms or clauses:
system_variable
ALL
BTI[TLE]
ERR[ORS] [{FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY|
TRIGGER|VIEW|TYPE|TYPE BODY} [schema.]name]
LNO
PARAMETERS [parameter_name]
PNO
REL[EASE]
REPF[OOTER]
REPH[EADER]
SGA
SPOO[L]
SQLCODE
TTI[TLE]
USER

1) . 显示当前环境变量的值:
Show all

2) . 显示当前在创建函数、存储过程、触发器、包等对象的错误信息
Show error
当创建一个函数、存储过程等出错时,变可以用该命令查看在那个地方出错及相应的出错信息,进行修改后再次进行编译。

3) . 显示初始化参数的值:
show PARAMETERS [parameter_name]

4) . 显示数据库的版本:
show REL[EASE]

5) . 显示SGA的大小
show SGA

6). 显示当前的用户名
show user

34.查询一个用户下的对象
SQL>select * from tab;
SQL>select * from user_objects;

35.查询一个用户下的所有的表
SQL>select * from user_tables;

36.查询一个用户下的所有的索引
SQL>select * from user_indexes;


37. 定义一个用户变量
方法有两个:
a. define
b. COL[UMN] [{column|expr} NEW_V[ALUE] variable [NOPRI[NT]|PRI[NT]]
OLD_V[ALUE] variable [NOPRI[NT]|PRI[NT]]

下面对每种方式给予解释:
a. Syntax
DEF[INE] [variable]|[variable = text]
定义一个用户变量并且可以分配给它一个CHAR值。

assign the value MANAGER to the variable POS, type:
SQL> DEFINE POS = MANAGER

assign the CHAR value 20 to the variable DEPTNO, type:
SQL> DEFINE DEPTNO = 20

list the definition of DEPTNO, enter
SQL> DEFINE DEPTNO
―――――――――――――――
DEFINE DEPTNO = ”20” (CHAR)

定义了用户变量POS后,就可以在sql*plus中用&POS或&&POS来引用该变量的值,sql*plus不会再提示你给变量输入值。

b. COL[UMN] [{column|expr} NEW_V[ALUE] variable [NOPRI[NT]|PRI[NT]]
NEW_V[ALUE] variable
指定一个变量容纳查询出的列值。
例:column col_name new_value var_name noprint
select col_name from table_name where ……..
将下面查询出的col_name列的值赋给var_name变量.

一个综合的例子:
得到一个列值的两次查询之差(此例为10秒之内共提交了多少事务):
column redo_writes new_value commit_count

select sum(stat.value) redo_writes
from v$sesstat stat, v$statname sn
where stat.statistic# = sn.statistic#
and sn.name = 'user commits';

-- 等待一会儿(此处为10秒);
execute dbms_lock.sleep(10);

set veri off
select sum(stat.value) - &commit_count commits_added
from v$sesstat stat, v$statname sn
where stat.statistic# = sn.statistic#
and sn.name = 'user commits';


38. 定义一个绑定变量
VAR[IABLE] [variable [NUMBER|CHAR|CHAR (n)|NCHAR|NCHAR (n) |VARCHAR2 (n)|NVARCHAR2 (n)|CLOB|NCLOB|REFCURSOR]]
定义一个绑定变量,该变量可以在pl/sql中引用。
可以用print命令显示该绑定变量的信息。
如:
column inst_num heading "Inst Num" new_value inst_num format 99999;
column inst_name heading "Instance" new_value inst_name format a12;
column db_name heading "DB Name" new_value db_name format a12;
column dbid heading "DB Id" new_value dbid format 9999999999 just c;

prompt
prompt Current Instance
prompt ~~~~~~~~~~~~~~~~

select d.dbid dbid
, d.name db_name
, i.instance_number inst_num
, i.instance_name inst_name
from v$database d,
v$instance i;

variable dbid number;
variable inst_num number;
begin
:dbid := &dbid;
:inst_num := &inst_num;
end;
/
说明:
在sql*plus中,该绑定变量可以作为一个存储过程的参数,也可以在匿名PL/SQL块中直接引用。为了显示用VARIABLE命令创建的绑定变量的值,可以用print命令

注意:
绑定变量不同于变量:
1. 定义方法不同
2. 引用方法不同
绑定变量::variable_name
变量:&variable_name or &&variable_name
3.在sql*plus中,可以定义同名的绑定变量与用户变量,但是引用的方法不同。

39. &与&&的区别
&用来创建一个临时变量,每当遇到这个临时变量时,都会提示你输入一个值。
&&用来创建一个持久变量,就像用用define命令或带new_vlaue字句的column命令创建的持久变量一样。当用&&命令引用这个变量时,不会每次遇到该变量就提示用户键入值,而只是在第一次遇到时提示一次。

如,将下面三行语句存为一个脚本文件,运行该脚本文件,会提示三次,让输入deptnoval的值:
select count(*) from emp where deptno = &deptnoval;
select count(*) from emp where deptno = &deptnoval;
select count(*) from emp where deptno = &deptnoval;

将下面三行语句存为一个脚本文件,运行该脚本文件,则只会提示一次,让输入deptnoval的值:
select count(*) from emp where deptno = &&deptnoval;
select count(*) from emp where deptno = &&deptnoval;
select count(*) from emp where deptno = &&deptnoval;

40.在输入sql语句的过程中临时先运行一个sql*plus命令(摘自www.itpub.com)
#
有没有过这样的经历? 在sql*plus中敲了很长的命令后, 突然发现想不起某个列的名字了, 如果取消当前的命令,待查询后再重敲, 那太痛苦了. 当然你可以另开一个sql*plus窗口进行查询, 但这里提供的方法更简单.

比如说, 你想查工资大于4000的员工的信息, 输入了下面的语句:

SQL> select deptno, empno, ename
2 from emp
3 where
这时, 你发现你想不起来工资的列名是什么了.

这种情况下, 只要在下一行以#开头, 就可以执行一条sql*plus命令, 执行完后, 刚才的语句可以继续输入

SQL>> select deptno, empno, ename
2 from emp
3 where
6 #desc emp
Name Null? Type
----------------------------------------- -------- --------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

6 sal > 4000;

DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7839 KING

41. SQLPlus中的快速复制和粘贴技巧(摘自www.cnoug.org)
1) 鼠标移至想要复制内容的开始
2) 用右手食指按下鼠标左键
3) 向想要复制内容的另一角拖动鼠标,与Word中选取内容的方法一样
4) 内容选取完毕后(所选内容全部反显),鼠标左键按住不动,用右手中指按鼠标右键
5) 这时,所选内容会自动复制到SQL*Plus环境的最后一行
posted @ 2008-05-23 22:43 meetrice 阅读(48) 评论(0) 编辑

先感谢木的{moond},要不是一次提供了那么多画原型图的工具,我现在还在Word和Visio里面打转呢。

这些软件能试用的我差不多都用了一下,其中觉得Axure的RP Pro 4挺好的,功能包括站点地图、流程设计、页面框架设计、简单交互设计等,可以生成HTML、Word等格式。

RP操作比用Dreamweaver简单多了,图片、文字、输入框等等所有组件全是可视化操作,可以很方便的实现网站交互内容的原型设计,可将以前死板的页面版式全部替换为有点击、链接效果的网页,nice~

同时可以为网站设计提供AJAX式的交互处理,RP提供一种动态层的组件,在同一页设定不同状态的效果,然后用链接、按钮等触发即可产生动态效果,这样网站设计就变得更加生动,意图也就更加直观。

可惜,这么好的软件只能试用30天,哪位兄台要是有解决方法一定要通知我,这里先谢了~

以下对RP5的新特性做了下简单翻译:

Axure RP Pro 5.0增加了众多新特性,并且着重增强了设计师间的协作、交互功能和更多的定制功能,生成也变的更快。

新功能包括:

1. 共享工程
1.1 可以在网络驱动器上创建共享工程,而不必非安装在服务器上
1.2 管理和便捷页面只需要通过简单的 check in / check out 即可
1.3 维护和浏览历史版本
1.4 更多介绍

2. 交互功能的增强
2.1 OnFocus 和 OnLostFocus 事件 (更多)
2.2 使用和禁止Widgets行为
2.3 模仿在图片上的锚点/热区行为 (更多)
2.4 移动动态层(Dynamic Panels)行为 (更多)
2.5 在其他行为运行之前暂停当前行为
2.6 页面间多达25个变量的储存

3. 规范的增强
3.1 可以更快的把演示生成为Microsoft Word 2007格式(使用Microsoft Office兼容包可与Microsoft Word 2000+兼容)
3.2 有1栏和2栏布局的选项
3.3 可以更简单的定制Word模板
3.4 有更多新选项去配置规范内容

4. 更多增强
4.1 优化Tab交互
4.2 可以选择与主窗体分离(比如Sitemap和Widgets)
4.3 有更好的保存机制来处理关闭和重开一个文件
4.4 带有梯度和透明设置的颜色工具
4.5 打印设置是被保存的

查看原文

同时提示一下:如果之前装过RP4,并且有license的话,RP5可以直接使用,
是作为免费升级的,当然,你也可以只当下来看看,有30天试用

=======================================================================

互联网行业产品经理的一项重要工作,就是进行产品原型设计(Prototype Design)。而产品原型设计最基础的工作,就是结合批注、大量的说明以及流程图画框架图wireframe,将自己的产品原型完整而准确的表述给UI、UE、程序工程师,市场人员,并通过沟通会议,反复修改prototype 直至最终确认,开始投入执行。

进行产品原型设计的软件工具也有很多种,我写的这个教程所介绍的Axure RP,是taobao、dangdang等国内大型网络公司的团队在推广使用的原型设计软件。同时,此软件也在产品经理圈子中广为流传。之所以Axure RP得到了大家的认同和推广,正是因为其简便的操作和使用,符合了产品经理、交互设计师们的需求。

在正式谈Axure RP之前,我们先来看看做产品原型设计,现在大致有哪些工具可以使用,而他们的利弊何在。
纸笔:简单易得,上手难度为零。有力于瞬间创意的产生与记录,有力于对文档即时的讨论与修改。但是保真度不高,难以表述页面流程,更难以表述交互信息与程序需求细节。
Word:上手难度普通。可以画wireframe,能够画页面流程,能够使用批注与文字说明。但是对交互表达不好,也不利于演示。
PPT:上手难度普通。易于画框架图,易于做批注,也可以表达交互流程,也擅长演示。但是不利于大篇幅的文档表达。
Visio:功能相对比较复杂。善于画流程图,框架图。不利于批注与大篇幅的文字说明。同样不利于交互的表达与演示。
Photshop/fireworks:操作难度相对较大,易于画框架图、流程图。不利于表达交互设计,不擅长文字说明与批注。
Dreamweave:操作难度大,需要基础的html知识。易于画框架图、流程图、表达交互设计。不擅长文字说明与批注。

以上这些工具,都是产品经理经常会使用到的,但是从根本上来说,这些工具都不是做prototype design的专门利器,需要根据产品开发不同的目的,不同的开发阶段,选择不同的工具搭配使用,才能达到表达、沟通的目的。

比如使用纸笔,更适合在产品创意阶段使用,可以快速记录闪电般的思路和灵感;也可以在即时讨论沟通时使用,通过图形快速表达自己的产品思路,及时的画出来,是再好不过的方法。而word则适合在用文字详细表达产品,对产品进行细节说明时使用,图片结合文字的排版,是word最擅长的工作。而ppt自然是演示时更好。visio则可以适用于各种流程图、关系图的表达,更可通过画use case 获取用户需求。PS/FW是图片处理的工具,DW则是所见即所得的网页开发软件,这些是设计师的看家本领,对于普通的产品经理来说,需要耗费太多的精力去掌握。

其实每件工具,每个软件,在创造它的初期,软件设计师们都给它赋予了性格、气质。因为每个工具的产生,都是为了满足人类的某一方面需求。比如锄头是锄土的,起子是起螺丝的,电熨斗是烫衣服的。但是不同的工具都有自己的工作领域,在其他领域它并不擅长。而以上的软件在创造的初期,并非为了帮助产品经理、ue完成产品原型设计,因此他们都不能在prototype design 这件工作上得心应手。而Axure RP正是在互联网产品大张其道的前提下,为满足prototype design创建的需求,应运而生。

Axure RP 能帮助网站需求设计者,快捷而简便的创建 基于目录组织的原型文档、功能说明、交互界面以及带注释的wireframe网页,并可自动生成用于演示的网页文件和word文档,以提供演示与开发。

没错!Axure RP 的特点是:

  • 快速创建带注释的wireframe文件,并可根据所设置的时间周期,软件自动保存文档,确保文件安全。
  • 在不写任何一条html与javascript语句的情况下,通过创建的文档以及相关条件和注释,一键生成html prototype演示。
  • 根据设计稿,一键生成一致而专业的word版本的原型设计文档。

说到这里相信很多人已经激起了兴趣,但是在开始学习之前,我认为我们还是有必要先了解一下软件短短的历史,创造这一软件的公司-Axure Software Solutions, Inc.该公司创建于2002年五月,Axure RP是这一软件公司的旗舰产品,2003年一月Axure RP第一版本上线发表,至今已经正式发行到了第四个版本,而我提笔写到这里的时候,Axure 5.0版本beta版本已经正式提供下载试用,虽然我已经下载使用,但是我想,写教程还是应该先从稳定的4.6版说起,至于5.0版,我们可以伴随着软件一起成长。

接下来我会结合图片,分几个步骤分享我对Axure的认识,
一、 界面与功能
二、 工具栏
三、 站点地图
四、 组件与使用方法
五、 复用模板与使用
六、 交互功能与注释
七、 实例

当然,在书写的过程中我会根据具体的情况再进行调整,尽量做到图文并茂,易于理解。写这个教程的目的,一方面为自己熟悉与更加理解Axure,另一方面也鞭策自己完善自己的blog网站www.2tan.net,同时也希望以自己的绵薄之力,为希望学习Axure的朋友分享一点经验。由于这是我第一次尝试写教程,难免会出现偏颇,也希望朋友们能够不吝赐教,共同进步。

另,为e文好的朋友附上自学Axure RP的几个途径:
1、 打开软件,按F1调取帮助文档,对照文档学习。
2、 登录http://www.axure.com/au-home.aspx 查看flash视频学习。
3、 登录 Axure 博客 http://axure.com/cs/blogs/Default.aspx,了解软件最新信息。
4、 登录讨论组http://axure.com/cs/forums/Default.aspx,参与讨论。

并提供Axure RP pro 4.6版本的下载
http://www.2tan.net/LoadMod.asp?plugins=downloadForPJBlog
由于放存软件的网络硬盘在下载数量不多的情况下可能会删除文件,如遇到死链接,可留言给我,我将重新上传:)
(软件仅供学习使用,反对商业用途 -_-!!!)


Name:3ddown
Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq+7w1RH97k5MWctqVHA
posted @ 2008-05-23 22:41 meetrice 阅读(3377) 评论(0) 编辑
最近,我面试了一个有五年 Web 应用程序开发经验的软件开发人员。四年半来她一直在从事 JavaScript 相关的工作,她自认为 JavaScript 技能非常好,但在不久之后我就发现实际上她对 JavaScript 知之甚少。话虽这样说,但我确实没有责备她的意思。JavaScript 真的是很有趣。很多人(包括我自己,直到最近!)都认为自己很擅长 JavaScript 语言,因为他们都知道 C/C++/C#,或者有一些以前的编程经验。

  在某种程度上,这种假设并不是完全没有根据的。用 JavaScript 很容易做些简单的事情。入门的门槛很低,该语言很宽松,它不需要您知道很多细节就可以开始用它进行编码。甚至非编程人员也可能用它在几个小时内为主页编写一些有用的脚本。

  的确,直到最近,仅仅凭借 MSDN® DHTML 参考资料和我的 C++/C# 经验,我也总能勉强利用这点 JavaScript 知识完成一些任务。只是当我开始编写真实的 AJAX 应用程序时,我才意识到实际上我的 JavaScript 知识还非常不够。这个新一代的 Web 应用程序的复杂性和交互性需要程序员以完全不同的方法来编写 JavaScript 代码。它们是真正的 JavaScript 应用程序!我们在编写一次性脚本时一直采用的方法已完全不再有效。

  面向对象编程 (OOP) 是一种流行的编程方法,很多 JavaScript 库中都使用这种方法,以便更好地管理和维护基本代码。JavaScript 支持 OOP,但与诸如 C++、C# 或 Visual Basic® 等流行的 Microsoft® .NET Framework 兼容语言相比,它支持 OOP 的方式非常不同,因此主要使用这些语言的开发人员开始可能会觉得在 JavaScript 中使用 OOP 很奇怪而且不直观。我写本文就是为了深入讨论 JavaScript 语言实际上如何支持面向对象编程,以及您如何使用这一支持在 JavaScript 中高效地进行面向对象开发。下面首先讨论对象(还能先讨论其他别的什么呢?)。

  JavaScript 对象是词典

  在 C++ 或 C# 中,在谈论对象时,是指类或结构的实例。对象有不同的属性和方法,具体取决于将它们实例化的模板(即类)。而 JavaScript 对象却不是这样。在 JavaScript 中,对象只是一组名称/值对,就是说,将 JavaScript 对象视为包含字符串关键字的词典。我们可以使用熟悉的"."(点)运算符或"[]"运算符,来获得和设置对象的属性,这是在处理词典时通常采用的方法。以下代码段

  var userObject = new Object();
  userObject.lastLoginTime = new Date();
  alert(userObject.lastLoginTime);

  的功能与下面的代码段完全相同:

  var userObject = {}; // equivalent to new Object()
  userObject["lastLoginTime"] = new Date();
  alert(userObject["lastLoginTime"]);

  我们还可以直接在 userObject 的定义中定义 lastLoginTime 属性,如下所示:

  var userObject = ;
  alert(userObject.lastLoginTime);

  注意,它与 C# 3.0 对象初始值非常相似。而且,熟悉 Python 的人会发现在第二和第三个代码段中实例化 userObject 的方法与在 Python 中指定词典的方法完全相同。唯一的差异是 JavaScript 对象/词典只接受字符串关键字,而不是像 Python 词典那样接受可哈希化的对象。

  这些示例还显示 JavaScript 对象比 C++ 或 C# 对象具有更大的可延展性。您不必预先声明属性 lastLoginTime - 如果 userObject 没有该名称的属性,该属性将被直接添加到 userObject。如果记住 JavaScript 对象是词典,您就不会对此感到吃惊了,毕竟,我们一直在向词典添加新关键字(和其各自的值)。

  这样,我们就有了对象属性。对象方法呢?同样,JavaScript 与 C++/C# 不同。若要理解对象方法,首先需要仔细了解一下 JavaScript 函数。 JavaScript 函数是最棒的

  在很多编程语言中,函数和对象通常被视为两样不同的东西。在 JavaScript 中,其差别很模糊 - JavaScript 函数实际上是具有与它关联的可执行代码的对象。请如此看待普通函数:

  function func(x) {
  alert(x);
  }
  func("blah");

  这就是通常在 JavaScript 中定义函数的方法。但是,还可以按以下方法定义该函数,您在此创建匿名函数对象,并将它赋给变量 func

  var func = function(x) {
  alert(x);
  };
  func("blah2");

  甚至也可以像下面这样,使用 Function 构造函数:

  var func = new Function("x", "alert(x);");
  func("blah3");

  此示例表明函数实际上只是支持函数调用操作的对象。最后一个使用 Function 构造函数来定义函数的方法并不常用,但它展示的可能性非常有趣,因为您可能注意到,该函数的主体正是 Function 构造函数的 String 参数。这意味着,您可以在运行时构造任意函数。

  为了进一步演示函数是对象,您可以像对其他任何 JavaScript 对象一样,在函数中设置或添加属性:

  function sayHi(x) {
  alert("Hi, " + x + "!");
  }
  sayHi.text = "Hello World!";
  sayHi["text2"] = "Hello World... again.";
  alert(sayHi["text"]); // displays "Hello World!"
  alert(sayHi.text2); // displays "Hello World... again."
 作为对象,函数还可以赋给变量、作为参数传递给其他函数、作为其他函数的值返回,并可以作为对象的属性或数组的元素进行存储等等。

// assign an anonymous function to a variable
var greet = function(x) {
alert("Hello, " + x);
};
greet("MSDN readers");

// passing a function as an argument to another
function square(x) {
return x * x;
}
function operateOn(num, func) {
return func(num);
}
// displays 256
alert(operateOn(16, square));

// functions as return values
function makeIncrementer() {
return function(x) { return x + 1; };
}
var inc = makeIncrementer();
// displays 8
alert(inc(7));

// functions stored as array elements
var arr = [];
arr[0] = function(x) { return x * x; };
arr[1] = arr[0](2);
arr[2] = arr[0](arr[1]);
arr[3] = arr[0](arr[2]);
// displays 256
alert(arr[3]);

// functions as object properties
var obj = { "toString" : function() { return "This is an object."; } };
// calls obj.toString()
alert(obj);

  记住这一点后,向对象添加方法将是很容易的事情:只需选择名称,然后将函数赋给该名称。因此,我通过将匿名函数分别赋给相应的方法名称,在对象中定义了三个方法:

  var myDog = {
  "name" : "Spot",
  "bark" : function() ,
  "displayFullName" : function() {
  alert(this.name + " The Alpha Dog");
  },
  "chaseMrPostman" : function() {
  // implementation beyond the scope of this article
  }
  };
  myDog.displayFullName();
  myDog.bark(); // Woof!
C++/C# 开发人员应当很熟悉 displayFullName 函数中使用的"this"关键字 - 它引用一个对象,通过对象调用方法(使用 Visual Basic 的开发人员也应当很熟悉它,它在 Visual Basic 中叫做"Me")。因此在上面的示例中,displayFullName 中的"this"的值是 myDog 对象。但是,"this"的值不是静态的。通过不同对象调用"this"时,它的值也会更改以便指向相应的对象,如下所示。

function displayQuote() {
// the value of "this" will change; depends on
// which object it is called through
alert(this.memorableQuote);
}

var williamShakespeare = {
"memorableQuote": "It is a wise father that knows his own child.",
"sayIt" : displayQuote
};

var markTwain = {
"memorableQuote": "Golf is a good walk spoiled.",
"sayIt" : displayQuote
};

var oscarWilde = {
"memorableQuote": "True friends stab you in the front."
// we can call the function displayQuote
// as a method of oscarWilde without assigning it
// as oscarWilde's method.
//"sayIt" : displayQuote
};

williamShakespeare.sayIt(); // true, true
markTwain.sayIt(); // he didn't know where to play golf

// watch this, each function has a method call()
// that allows the function to be called as a
// method of the object passed to call() as an
// argument.
// this line below is equivalent to assigning
// displayQuote to sayIt, and calling oscarWilde.sayIt().
displayQuote.call(oscarWilde); // ouch!

  最后一行表示的是将函数作为对象的方法进行调用的另一种方式。请记住,JavaScript 中的函数是对象。每个函数对象都有一个名为 call 的方法,它将函数作为第一个参数的方法进行调用。就是说,作为函数第一个参数传递给 call 的任何对象都将在函数调用中成为"this"的值。这一技术对于调用基类构造函数来说非常有用,稍后将对此进行介绍。

  有一点需要记住,绝不要调用包含"this"(却没有所属对象)的函数。否则,将违反全局命名空间,因为在该调用中,"this"将引用全局对象,而这必然会给您的应用程序带来灾难。例如,下面的脚本将更改 JavaScript 的全局函数 isNaN 的行为。一定不要这样做!

  alert("NaN is NaN: " + isNaN(NaN));
  function x() {
  this.isNaN = function() {
  return "not anymore!";
  };
  }
  // alert!!! trampling the Global object!!!
  x();
  alert("NaN is NaN: " + isNaN(NaN));

  到这里,我们已经介绍了如何创建对象,包括它的属性和方法。但如果注意上面的所有代码段,您会发现属性和方法是在对象定义本身中进行硬编码的。但如果需要更好地控制对象的创建,该怎么做呢?例如,您可能需要根据某些参数来计算对象的属性值。或者,可能需要将对象的属性初始化为仅在运行时才能获得的值。也可能需要创建对象的多个实例(此要求非常常见)。

  在 C# 中,我们使用类来实例化对象实例。但 JavaScript 与此不同,因为它没有类。您将在下一节中看到,您可以充分利用这一情况:函数在与"new"运算符一起使用时,函数将充当构造函数。构造函数而不是类

  前面提到过,有关 JavaScript OOP 的最奇怪的事情是,JavaScript 不像 C# 或 C++ 那样,它没有类。在 C# 中,在执行类似下面的操作时:

  Dog spot = new Dog();

  将返回一个对象,该对象是 Dog 类的实例。但在 JavaScript 中,本来就没有类。与访问类最近似的方法是定义构造函数,如下所示:

  function DogConstructor(name) {
  this.name = name;
  this.respondTo = function(name) {
  if(this.name == name) {
  alert("Woof");
  }
  };
  }
  var spot = new DogConstructor("Spot");
  spot.respondTo("Rover"); // nope
  spot.respondTo("Spot"); // yeah!

  那么,结果会怎样呢?暂时忽略 DogConstructor 函数定义,看一看这一行:

  var spot = new DogConstructor("Spot");

  "new"运算符执行的操作很简单。首先,它创建一个新的空对象。然后执行紧随其后的函数调用,将新的空对象设置为该函数中"this"的值。换句话说,可以认为上面这行包含"new"运算符的代码与下面两行代码的功能相当:

  // create an empty object
  var spot = {};
  // call the function as a method of the empty object
  DogConstructor.call(spot, "Spot");

  正如在 DogConstructor 主体中看到的那样,调用此函数将初始化对象,在调用期间关键字"this"将引用此对象。这样,就可以为对象创建模板!只要需要创建类似的对象,就可以与构造函数一起调用"new",返回的结果将是一个完全初始化的对象。这与类非常相似,不是吗?实际上,在 JavaScript 中构造函数的名称通常就是所模拟的类的名称,因此在上面的示例中,可以直接命名构造函数 Dog:

  // Think of this as class Dog
  function Dog(name) {
  // instance variable
  this.name = name;
  // instance method? Hmmm...
  this.respondTo = function(name) {
  if(this.name == name) {
  alert("Woof");
  }
  };
  }
  var spot = new Dog("Spot");
在上面的 Dog 定义中,我定义了名为 name 的实例变量。使用 Dog 作为其构造函数所创建的每个对象都有它自己的实例变量名称副本(前面提到过,它就是对象词典的条目)。这就是希望的结果。毕竟,每个对象都需要它自己的实例变量副本来表示其状态。但如果看看下一行,就会发现每个 Dog 实例也都有它自己的 respondTo 方法副本,这是个浪费;您只需要一个可供各个 Dog 实例共享的 respondTo 实例!通过在 Dog 以外定义 respondTo,可以避免此问题,如下所示:
  function respondTo() {
  // respondTo definition
  }
  function Dog(name) {
  this.name = name;
  // attached this function as a method of the object
  this.respondTo = respondTo;
  }

  这样,所有 Dog 实例(即用构造函数 Dog 创建的所有实例)都可以共享 respondTo 方法的一个实例。但随着方法数的增加,维护工作将越来越难。最后,基本代码中将有很多全局函数,而且随着"类"的增加,事情只会变得更加糟糕(如果它们的方法具有相似的名称,则尤甚)。但使用原型对象可以更好地解决这个问题,这是下一节的主题。

  原型

  在使用 JavaScript 的面向对象编程中,原型对象是个核心概念。在 JavaScript 中对象是作为现有示例(即原型)对象的副本而创建的,该名称就来自于这一概念。此原型对象的任何属性和方法都将显示为从原型的构造函数创建的对象的属性和方法。可以说,这些对象从其原型继承了属性和方法。当您创建如下所示的新 Dog 对象时:

  var buddy = new Dog("Buddy");

  buddy 所引用的对象将从它的原型继承属性和方法,尽管仅从这一行可能无法明确判断原型来自哪里。对象 buddy 的原型来自构造函数(在这里是函数 Dog)的属性。

  在 JavaScript 中,每个函数都有名为"prototype"的属性,用于引用原型对象。此原型对象又有名为"constructor"的属性,它反过来引用函数本身。这是一种循环引用,图 1 更好地说明了这种循环关系。

图 3 每个函数的原型都有一个 Constructor 属性
图 1 每个函数的原型都有一个 Constructor 属性

  现在,通过"new"运算符用函数(上面示例中为 Dog)创建对象时,所获得的对象将继承 Dog.prototype 的属性。在图 1 中,可以看到 Dog.prototype 对象有一个回指 Dog 函数的构造函数属性。这样,每个 Dog 对象(从 Dog.prototype 继承而来)都有一个回指 Dog 函数的构造函数属性。图 2 显示了构造函数、原型对象以及用它们创建的对象之间的这一关系。

var spot = new Dog("Spot");

// Dog.prototype is the prototype of spot
alert(Dog.prototype.isPrototypeOf(spot));

// spot inherits the constructor property
// from Dog.prototype
alert(spot.constructor == Dog.prototype.constructor);
alert(spot.constructor == Dog);

// But constructor property doesn't belong
// to spot. The line below displays "false"
alert(spot.hasOwnProperty("constructor"));

// The constructor property belongs to Dog.prototype
// The line below displays "true"
alert(Dog.prototype.hasOwnProperty("constructor"));

图 5 实例继承其原型
图 2 实例继承其原型
 某些读者可能已经注意到代码中对 hasOwnProperty 和 isPrototypeOf 方法的调用。这些方法是从哪里来的呢?它们不是来自 Dog.prototype。实际上,在 Dog.prototype 和 Dog 实例中还可以调用其他方法,比如 toString、toLocaleString 和 valueOf,但它们都不来自 Dog.prototype。您会发现,就像 .NET Framework 中的 System.Object 充当所有类的最终基类一样,JavaScript 中的 Object.prototype 是所有原型的最终基础原型。(Object.prototype 的原型是 null。)

  在此示例中,请记住 Dog.prototype 是对象。它是通过调用 Object 构造函数创建的(尽管它不可见):

  Dog.prototype = new Object();

  因此,正如 Dog 实例继承 Dog.prototype 一样,Dog.prototype 继承 Object.prototype。这使得所有 Dog 实例也继承了 Object.prototype 的方法和属性。

  每个 JavaScript 对象都继承一个原型链,而所有原型都终止于 Object.prototype。注意,迄今为止您看到的这种继承是活动对象之间的继承。它不同于继承的常见概念,后者是指在声明类时类之间的发生的继承。因此,JavaScript 继承动态性更强。它使用简单算法实现这一点,如下所示:当您尝试访问对象的属性/方法时,JavaScript 将检查该属性/方法是否是在该对象中定义的。如果不是,则检查对象的原型。如果还不是,则检查该对象的原型的原型,如此继续,一直检查到 Object.prototype。图 3 说明了此解析过程。

图 6 在原型链中解析 toString() 方法
图 3 在原型链中解析 toString() 方法

  JavaScript 动态地解析属性访问和方法调用的方式产生了一些特殊效果:

  继承原型对象的对象上可以立即呈现对原型所做的更改,即使是在创建这些对象之后。

  如果在对象中定义了属性/方法 X,则该对象的原型中将隐藏同名的属性/方法。例如,通过在 Dog.prototype 中定义 toString 方法,可以改写 Object.prototype 的 toString 方法。

  更改只沿一个方向传递,即从原型到它的派生对象,但不能沿相反方向传递。代码 说明了这些效果。显示了如何解决前面遇到的不需要的方法实例的问题。通过将方法放在原型内部,可以使对象共享方法,而不必使每个对象都有单独的函数对象实例。在此示例中,rover 和 spot 共享 getBreed 方法,直至在 spot 中以任何方式改写 toString 方法。此后,spot 有了它自己版本的 getBreed 方法,但 rover 对象和用新 GreatDane 创建的后续对象仍将共享在 GreatDane.prototype 对象中定义的那个 getBreed 方法实例。

function GreatDane() { }

var rover = new GreatDane();
var spot = new GreatDane();

GreatDane.prototype.getBreed = function() {
return "Great Dane";
};

// Works, even though at this point
// rover and spot are already created.
alert(rover.getBreed());

// this hides getBreed() in GreatDane.prototype
spot.getBreed = function() {
return "Little Great Dane";
};
alert(spot.getBreed());

// but of course, the change to getBreed
// doesn't propagate back to GreatDane.prototype
// and other objects inheriting from it,
// it only happens in the spot object
alert(rover.getBreed());

  静态属性和方法

  有时,您需要绑定到类而不是实例的属性或方法,也就是,静态属性和方法。在 JavaScript 中很容易做到这一点,因为函数是可以按需要设置其属性和方法的对象。由于在 JavaScript 中构造函数表示类,因此可以通过在构造函数中设置静态方法和属性,直接将它们添加到类中,如下所示:

  function DateTime()
  // set static method now()
  DateTime.now = function() {
  return new Date();
  };
  alert(DateTime.now());

  在 JavaScript 中调用静态方法的语法与在 C# 中几乎完全相同。这不应当让人感到吃惊,因为构造函数的名称实际上是类的名称。这样,就有了类、公用属性/方法,以及静态属性/方法。还需要其他什么吗?当然,私有成员。但 JavaScript 本身并不支持私有成员(同样,也不支持受保护成员)。任何人都可以访问对象的所有属性和方法。但我们有办法让类中包含私有成员,但在此之前,您首先需要理解闭包。

  闭包

  我没有自觉地学习过 JavaScript。我必须快点了解它,因为我发现如果没有它,在实际工作中编写 AJAX 应用程序的准备就会不充分。开始,我感到我的编程水平好像降了几个级别。(JavaScript!我的 C++ 朋友会怎么说?)但一旦我克服最初的障碍,我就发现 JavaScript 实际上是功能强大、表现力强而且非常简练的语言。它甚至具有其他更流行的语言才刚刚开始支持的功能。

  JavaScript 的更高级功能之一是它支持闭包,这是 C# 2.0 通过它的匿名方法支持的功能。闭包是当内部函数(或 C# 中的内部匿名方法)绑定到它的外部函数的本地变量时所发生的运行时现象。很明显,除非此内部函数以某种方式可被外部函数访问,否则它没有多少意义。示例可以更好说明这一点。 假设需要根据一个简单条件筛选一个数字序列,这个条件是:只有大于 100 的数字才能通过筛选,并忽略其余数字。为此,可以编写类似的函数。

function filter(pred, arr) {
var len = arr.length;
var filtered = []; // shorter version of new Array();
// iterate through every element in the array...
for(var i = 0; i < len; i++) {
var val = arr[i];
// if the element satisfies the predicate let it through
if(pred(val)) {
filtered.push(val);
}
}
return filtered;
}

var someRandomNumbers = [12, 32, 1, 3, 2, 2, 234, 236, 632,7, 8];
var numbersGreaterThan100 = filter(
function(x) { return (x > 100) ? true : false; },
someRandomNumbers);

// displays 234, 236, 632
alert(numbersGreaterThan100);

  但是,现在要创建不同的筛选条件,假设这次只有大于 300 的数字才能通过筛选,则可以编写下面这样的函数:

  var greaterThan300 = filter(
  function(x) ,
  someRandomNumbers);

  然后,也许需要筛选大于 50、25、10、600 如此等等的数字,但作为一个聪明人,您会发现它们全部都有相同的谓词"greater than",只有数字不同。因此,可以用类似下面的函数分开各个数字:

  function makeGreaterThanPredicate(lowerBound) {
  return function(numberToCheck) {
  return (numberToCheck > lowerBound) ? true : false;
  };
  }

  这样,您就可以编写以下代码:

  var greaterThan10 = makeGreaterThanPredicate(10);
  var greaterThan100 = makeGreaterThanPredicate(100);
  alert(filter(greaterThan10, someRandomNumbers));
  alert(filter(greaterThan100, someRandomNumbers));

  通过观察函数 makeGreaterThanPredicate 返回的内部匿名函数,可以发现,该匿名内部函数使用 lowerBound,后者是传递给 makeGreaterThanPredicate 的参数。按照作用域的一般规则,当 makeGreaterThanPredicate 退出时,lowerBound 超出了作用域!但在这里,内部匿名函数仍然携带 lowerBound,甚至在 makeGreaterThanPredicate 退出之后的很长时间内仍然如此。这就是我们所说的闭包:因为内部函数关闭了定义它的环境(即外部函数的参数和本地变量)。

  开始可能感觉不到闭包的功能很强大。但如果应用恰当,它们就可以非常有创造性地帮您将想法转换成代码,这个过程非常有趣。在 JavaScript 中,闭包最有趣的用途之一是模拟类的私有变量。模拟私有属性

  现在介绍闭包如何帮助模拟私有成员。正常情况下,无法从函数以外访问函数内的本地变量。函数退出之后,由于各种实际原因,该本地变量将永远消失。但是,如果该本地变量被内部函数的闭包捕获,它就会生存下来。这一事实是模拟 JavaScript 私有属性的关键。假设有一个 Person 类:

  function Person(name, age) {
  this.getName = function() ;
  this.setName = function(newName) ;
  this.getAge = function() ;
  this.setAge = function(newAge) ;
  }

  参数 name 和 age 是构造函数 Person 的本地变量。Person 返回时,name 和 age 应当永远消失。但是,它们被作为 Person 实例的方法而分配的四个内部函数捕获,实际上这会使 name 和 age 继续存在,但只能严格地通过这四个方法访问它们。因此,您可以:

  var ray = new Person("Ray", 31);
  alert(ray.getName());
  alert(ray.getAge());
  ray.setName("Younger Ray");
  // Instant rejuvenation!
  ray.setAge(22);
  alert(ray.getName() + " is now " + ray.getAge() +
  " years old.");

  未在构造函数中初始化的私有成员可以成为构造函数的本地变量,如下所示:

  function Person(name, age) {
  var occupation;
  this.getOccupation = function() ;
  this.setOccupation = function(newOcc) { occupation =
  newOcc; };
  // accessors for name and age
  }

  注意,这些私有成员与我们期望从 C# 中产生的私有成员略有不同。在 C# 中,类的公用方法可以访问它的私有成员。但在 JavaScript 中,只能通过在其闭包内拥有这些私有成员的方法来访问私有成员(由于这些方法不同于普通的公用方法,它们通常被称为特权方法)。因此,在 Person 的公用方法中,仍然必须通过私有成员的特权访问器方法才能访问私有成员:

  Person.prototype.somePublicMethod = function() {
  // doesn't work!
  // alert(this.name);
  // this one below works
  alert(this.getName());
  };

  Douglas Crockford 是著名的发现(或者也许是发布)使用闭包来模拟私有成员这一技术的第一人。他的网站 javascript.crockford.com 包含有关 JavaScript 的丰富信息,任何对 JavaScript 感兴趣的开发人员都应当仔细研读。从类继承

  到这里,我们已经了解了构造函数和原型对象如何使您在 JavaScript 中模拟类。您已经看到,原型链可以确保所有对象都有 Object.prototype 的公用方法,以及如何使用闭包来模拟类的私有成员。但这里还缺少点什么。您尚未看到如何从类派生,这在 C# 中是每天必做的工作。遗憾的是,在 JavaScript 中从类继承并非像在 C# 中键入冒号即可继承那样简单,它需要进行更多操作。另一方面,JavaScript 非常灵活,可以有很多从类继承的方式。

  例如,有一个基类 Pet,它有一个派生类 Dog,如图 4 所示。这个在 JavaScript 中如何实现呢?Pet 类很容易。您已经看见如何实现它了:

图 9 类
图 4 类

  // class Pet
  function Pet(name) {
  this.getName = function() ;
  this.setName = function(newName) ;
  }
  Pet.prototype.toString = function() {
  return "This pet's name is: " + this.getName();
  };
  // end of class Pet
  var parrotty = new Pet("Parrotty the Parrot");
  alert(parrotty);

  现在,如何创建从 Pet 派生的类 Dog 呢?在图 4 中可以看到,Dog 有另一个属性 breed,它改写了 Pet 的 toString 方法(注意,JavaScript 的约定是方法和属性名称使用 camel 大小写,而不是在 C# 中建议的 Pascal 大小写)。

// class Dog : Pet
// public Dog(string name, string breed)
function Dog(name, breed) {
// think Dog : base(name)
Pet.call(this, name);
this.getBreed = function() { return breed; };
// Breed doesn't change, obviously! It's read only.
// this.setBreed = function(newBreed) { name = newName; };
}

// this makes Dog.prototype inherits
// from Pet.prototype
Dog.prototype = new Pet();

// remember that Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() {
return "This dog's name is: " + this.getName() +
", and its breed is: " + this.getBreed();
};
// end of class Dog

var dog = new Dog("Buddy", "Great Dane");
// test the new toString()
alert(dog);

// Testing instanceof (similar to the is operator)
// (dog is Dog)? yes
alert(dog instanceof Dog);
// (dog is Pet)? yes
alert(dog instanceof Pet);
// (dog is Object)? yes
alert(dog instanceof Object);

  所使用的原型 - 替换技巧正确设置了原型链,因此假如使用 C#,测试的实例将按预期运行。而且,特权方法仍然会按预期运行。模拟命名空间

  在 C++ 和 C# 中,命名空间用于尽可能地减少名称冲突。例如,在 .NET Framework 中,命名空间有助于将 Microsoft.Build.Task.Message 类与 System.Messaging.Message 区分开来。JavaScript 没有任何特定语言功能来支持命名空间,但很容易使用对象来模拟命名空间。如果要创建一个 JavaScript 库,则可以将它们包装在命名空间内,而不需要定义全局函数和类,如下所示:

  var MSDNMagNS = {};
  MSDNMagNS.Pet = function(name) ;
  MSDNMagNS.Pet.prototype.toString = function() ;
  var pet = new MSDNMagNS.Pet("Yammer");

  命名空间的一个级别可能不是唯一的,因此可以创建嵌套的命名空间:

  var MSDNMagNS = {};
  // nested namespace "Examples"
  MSDNMagNS.Examples = {};
  MSDNMagNS.Examples.Pet = function(name) ;
  MSDNMagNS.Examples.Pet.prototype.toString = function() ;
  var pet = new MSDNMagNS.Examples.Pet("Yammer");

  可以想象,键入这些冗长的嵌套命名空间会让人很累。 幸运的是,库用户可以很容易地为命名空间指定更短的别名:

  // MSDNMagNS.Examples and Pet definition...
  // think "using Eg = MSDNMagNS.Examples;"
  var Eg = MSDNMagNS.Examples;
  var pet = new Eg.Pet("Yammer");
  alert(pet);

  如果看一下 Microsoft AJAX 库的源代码,就会发现库的作者使用了类似的技术来实现命名空间(请参阅静态方法 Type.registerNamespace 的实现)。有关详细信息,请参与侧栏"OOP 和 ASP.NET AJAX"。

  应当这样编写 JavaScript 代码吗?

  您已经看见 JavaScript 可以很好地支持面向对象的编程。尽管它是一种基于原型的语言,但它的灵活性和强大功能可以满足在其他流行语言中常见的基于类的编程风格。但问题是:是否应当这样编写 JavaScript 代码?在 JavaScript 中的编程方式是否应与 C# 或 C++ 中的编码方式相同?是否有更聪明的方式来模拟 JavaScript 中没有的功能?每种编程语言都各不相同,一种语言的最佳做法,对另一种语言而言则可能并非最佳。

  在 JavaScript 中,您已看到对象继承对象(与类继承类不同)。因此,使用静态继承层次结构建立很多类的方式可能并不适合 JavaScript。也许,就像 Douglas Crockford 在他的文章 Prototypal Inheritance in JavaScript 中说的那样,JavaScript 编程方式是建立原型对象,并使用下面的简单对象函数建立新的对象,而后者则继承原始对象:

  function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
  }

  然后,由于 JavaScript 中的对象是可延展的,因此可以方便地在创建对象之后,根据需要用新字段和新方法增大对象。

  这的确很好,但它不可否认的是,全世界大多数开发人员更熟悉基于类的编程。实际上,基于类的编程也会在这里出现。按照即将颁发的 ECMA-262 规范第 4 版(ECMA-262 是 JavaScript 的官方规范),JavaScript 2.0 将拥有真正的类。因此,JavaScript 正在发展成为基于类的语言。但是,数年之后 JavaScript 2.0 才可能会被广泛使用。同时,必须清楚当前的 JavaScript 完全可以用基于原型的风格和基于类的风格读取和写入 JavaScript 代码。

  展望

  随着交互式胖客户端 AJAX 应用程序的广泛使用,JavaScript 迅速成为 .NET 开发人员最重要的工具之一。但是,它的原型性质可能一开始会让更习惯诸如 C++、C# 或 Visual Basic 等语言的开发人员感到吃惊。我已发现我的 JavaScript 学习经历给予了我丰富的体验,虽然其中也有一些挫折。如果本文能使您的体验更加顺利,我会非常高兴,因为这正是我的目标。

posted @ 2008-05-23 22:40 meetrice 阅读(124) 评论(0) 编辑
前段时间写jsfw [ JavaScript FrameWork ],写完后发现每刷新一次内存就升大几百K,用一个小时IE内存占用高到一两百M。看了以下文章,五个分类我犯了四个,问题是找到了,不过改起来很累
---------------------------以下文章不知道是从哪Copy来的-------------------
在IE下的JS编程中,以下的编程方式都会造成即使关闭IE也无法释放内存的问题,下面分类给出:

1、给DOM对象添加的属性是一个对象的引用。范例:
var MyObject = {};
document.getElementById('myDiv').myProp = MyObject;
解决方法
在window.onunload事件中写上: document.getElementById('myDiv').myProp = null;


2、DOM对象与JS对象相互引用。范例:
function Encapsulator(element) {
   this.elementReference = element;
   element.myProp = this;
}
new   Encapsulator(document.getElementById('myDiv'));
解决方法
在onunload事件中写上: document.getElementById('myDiv').myProp = null;


3、给DOM对象用attachEvent绑定事件。范例:
function doClick() {}
element.attachEvent("onclick", doClick);
解决方法
在onunload事件中写上: element.detachEvent('onclick', doClick);


4、从外到内执行appendChild。这时即使调用removeChild也无法释放。范例:
var parentDiv =   document.createElement("div");
var childDiv = document.createElement("div");
document.body.appendChild(parentDiv);
parentDiv.appendChild(childDiv);
解决方法
从内到外执行appendChild:
var parentDiv =   document.createElement("div");
var childDiv = document.createElement("div");
parentDiv.appendChild(childDiv);
document.body.appendChild(parentDiv);


5、反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。范例:
for(i = 0; i < 5000; i++) {
   hostElement.text = "asdfasdfasdf";
}
这种方式相当于定义了5000个属性!
解决方法:
其实没什么解决方法:P~~~就是编程的时候尽量避免出现这种情况咯~~


说明:
1、以上资料均来源于微软官方的MSDN站点,链接地址:
http://msdn.microsoft.com/librar ... e_leak_patterns.asp
大家可以到上面这个地址中看到详细的说明,包括范例和图例都有。只是我英文不太好,看不太懂,如果我上述有失误或有需要补充的地方请大家指出。

2、对于第一条,事实上包括 element.onclick = funcRef 这种写法也算在其中,因为这也是一个对对象的引用。在页面onunload时应该释放掉。

3、对于第三条,在MSDN的英文说明中好像是说即使调用detachEvent也无法释放内存,因为在attachEvent的时候就已经造成内存“LEAK”了,不过detachEvent后情况还是会好一点。不知道是不是这样,请英文好的亲能够指出。

4、在实际编程中,这些内存问题的实际影响并不大,尤其是给客户使用时,客户对此绝不会有察觉,然而这些问题对于程序员来说却始终是个心病 --- 有这样的BUG心里总会觉得不舒服吧?能解决则给与解决,这样是最好的。事实上我在webfx.eae.net这样顶级的JS源码站点中,在它们的源码里都会看到采用上述解决方式进行内存的释放管理。
posted @ 2008-05-23 22:39 meetrice 阅读(1105) 评论(0) 编辑

Jash是一个基于DHTML开发的命令行JavaScript调试工具,用于调试当前打开的页面。通过该调试工具,你可以快速的进行脚本调试,查看dom、当前页面对象,函数、变量,跟踪执行堆栈,执行任意脚本及为页面定义css等,可运行于IE6+ 、FF1.5+、Safari 3 +下。
程序仅仅是一个大小约为30kb的js文件,无需安装,只需将js放入书签,随时都可以通过点击该书签调出,或者在自己程序中直接嵌入这个js文件即可。

Jash.js

Jash bookmarklet


用法:

<href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://www.billyreisinger.com/jash/source/latest/Jash.js';})();">点击这里调试</a>


posted @ 2008-05-23 22:38 meetrice 阅读(333) 评论(1) 编辑

最近在学习Ext,发现这个玩意虽然很强大,但是也太重量级了,没有几个月时间大概很难用好。自己直接学习Ext Api的过程中有不少的痛苦经历,进度也比较慢,经常看看别人的研究学习成果对于自己的学习还是很有帮助的,这里将几个不错的Ext学习站点收藏起来,便于以后自己参考学习。

JavaEye Ext交流区:http://www.javaeye.com/forums/tag/EXT
著名的技术社区JavaEye,这里Ext交流的人气在国内还算比较火热的。

blackant2的专栏:http://blog.csdn.net/blackant2/
该blog作者一直在对Ext的Api做翻译,当然也有很多对api的实例讲解,对于系统的学习很有帮助。

天晓得的专栏:http://blog.csdn.net/tianxiaode/
该blog作者主要以具体的实例讲解Ext的使用,便于将Ext的学习与具体应用相结合。

http://ajaxbbs.net/blog/index.php

http://www.family168.com/

http://www.family168.com/tutorial/extdoc/html/preface.html

posted @ 2008-05-23 22:37 meetrice 阅读(199) 评论(0) 编辑
 AnchorLayout是最简单的布局管理其,它只是将元素按照配置的属性在元素容器中进行定位。
    让我们看一下它的render方法以理解如果进行布局:

    onLayout : 
function(ct, target){
    Ext.layout.AnchorLayout.superclass.onLayout.call(
this, ct, target);
    
//获取元素的尺寸
    var size = this.getAnchorViewSize(ct, target);
    
var w = size.width, h = size.height;
    
if(w < 20 || h < 20){
        
return;
    }

    
// 获取容器的尺寸
    var aw, ah;
    
if(ct.anchorSize){
        
if(typeof ct.anchorSize == 'number'){
          aw 
= ct.anchorSize;
        }
else{
          aw 
= ct.anchorSize.width;
          ah 
= ct.anchorSize.height;
        }

    }
else{
    
//根据配置获取容器尺寸
        aw = ct.initialConfig.width;
        ah 
= ct.initialConfig.height;
    }

    
//遍历元素,并调用元素的setSize方法,继承自boxComponent的setSize方法则触发resize事件从而触发layout方法。
    var cs = ct.items.items, len = cs.length, i, c, a, cw, ch;
    
for(i = 0; i < len; i++){
        c 
= cs;
        
if(c.anchor){
          a 
= c.anchorSpec;
          
if(!a)// cache all anchor values
            var vs = c.anchor.split(' ');
            c.anchorSpec 
= a = {
                right: 
this.parseAnchor(vs[0], c.initialConfig.width, aw),
                bottom: 
this.parseAnchor(vs[1], c.initialConfig.height, ah)
            }
;
          }

          cw 
= a.right ? this.adjustWidthAnchor(a.right(w), c) : undefined;
          ch 
= a.bottom ? this.adjustHeightAnchor(a.bottom(h), c) : undefined;
          
if(cw || ch){
            c.setSize(cw 
|| undefined, ch || undefined);
          }

        }

    }

  }
,
posted @ 2008-05-23 22:35 meetrice 阅读(360) 评论(0) 编辑
  如果学习了Container,你回发现,在Ext2.0中,Container和Layout的关系是密不可分的。任何Container都需要在render方法中使用layout对象进行布局。
  让我们先看一下所有layout的父类:ContainerLayout。
  实际上,对容器及其item的渲染都是在layout对象的layout方法中实现的。而layout方法是在resize事件中触发的,基于性能的考虑,可以通过配置bufferResize属性实现延迟layout:
  onResize: function(){
    
if(this.container.collapsed){
        
return;
    }

    
var b = this.container.bufferResize;
    
if(b){
        
if(!this.resizeTask){
          
this.resizeTask = new Ext.util.DelayedTask(this.layout, this);
          
this.resizeBuffer = typeof b == 'number' ? b : 100;
        }

        
this.resizeTask.delay(this.resizeBuffer);
    }
else{
        
this.layout();
    }

  }


  lyout方法会遍历所有的Container子元素并对其进行render:
 
renderItem : function(c, position, target){
    
if(c && !c.rendered){
        c.render(target, position);
        
if(this.extraCls){
        
var t = c.getPositionEl ? c.getPositionEl() : c;
        t.addClass(
this.extraCls);
        }

        
if (this.renderHidden && c != this.activeItem) {
          c.hide();
        }

    }
else if(c && !this.isValidParent(c, target)){
        
if(this.extraCls){
          c.addClass(
this.extraCls);
        }

        
if(typeof position == 'number'){
          position 
= target.dom.childNodes[position];
        }

        target.dom.insertBefore(c.getEl().dom, position 
|| null);
        
if (this.renderHidden && c != this.activeItem) {
          c.hide();
        }

    }

  }


posted @ 2008-05-23 22:34 meetrice 阅读(437) 评论(0) 编辑
posted @ 2008-05-23 22:31 meetrice 阅读(1139) 评论(0) 编辑

在这里,我们引用Ext Overview中的Component life cycle对组件的功能进行相应的总结:
[list=1]

  • 配置项对象生效:
    组件对象的构造器会把全部的配置项传入到其子类中去,并且进行下列所有的步骤。
  • 组件的底层事件创建
    这些事件由组件对象负责触发。事件有enable, disable, beforeshow, show, beforehide, hide, beforerender, render, beforedestroy, destroy
  • 组件在组件管理器里登记
    initComponent这方法总是使用在子类中,就其本身而论,该方法是一个模板方法(template method),用于每个子类去现实任何所需的构造器逻辑(any needed constructor logic)。首先会创建类,然后组件对象各层次里面的每个类都应该调用superclass.initComponent。通过该方法,就可方便地实现(implement),或重写(Override)任意一层构造器的逻辑。
  • 加载插件(如果有的话)
    如果该组件有指定任何插件,这时便会初始化。
  • 渲染组件(如果必须的话)
    如果指定了组件的renderToapplyTo配置属性,那么渲染工作就会立即开始,否则意味着延时渲染(在layout对象的layout方法中也会对组件进行渲染),即等待到显式控制显示,或是其容器告知其显示的命令。
      渲染过程 Rendering
      [list=1]
    • 触发beforerender事件
      这是个可取消的事件,指定的句柄(handler)通过返回false可阻止组件进行渲染
    • 设置好容器
      如果没有指定一个容器,那么将使用位于DOM元素中组件的父节点作为容器。
    • 调用onRender方法 这是子类渲染最重要的一个步骤,由于该方法是一个模板方法(template method),用于每个子类去现实任何所需的渲染逻辑(any needed render logic)。首先会创建类,然后组件对象各层次里面的每个类都应调用superclass.onRender。通过该方法,就可方便地实现(implement),或重写(Override)任意一层渲染的逻辑。
    • 处理组件是“隐藏”状态 默认下,许多组件是由CSS样式类如"x-hidden"设置隐藏的。如果 autoShow所配置的值为true,这时就不会有这个"hide"样式类作用在该组件上
    • 自定义的类、样式生效 Custom class and/or style applied
      一切组件的子类都支持clsstyle 两种特殊的配置属性,分别用于指定用户自定义的CSS样式类和CSS规则。 推荐指定cls的方法来制定组件及其各部分的可视化设置。由于该样式类会套用在组件markup最外的一层元素,所以标准CSS规则会继承到组件下任何子元素的身上。
    • 触发render事件 The render event is fired
      这是组件通知成功渲染的一个步骤。这时,你可肯定地认为组件的DOM元素是可用的了。如果尝试在渲染之前访问组件,会抛出一个不可用的异常。
    • 调用了afterRender方法 The afterRender method is called
      这是另外一个实现或重写特定所需的“后渲染”逻辑的模板方法。每个子类应调用superclass.afterRender.
    • 组件被隐藏或禁用(如果有的话) The Component is hidden and/or disabled (if applicable)
      配置项hidden和disabled到这步生效
    • 所有状态感知的事件初始化(如果有的话) Any state-specific events are initialized (if applicable)
      状态感知的组件可由事件声明特殊加载和保存状态。如支持,加入此类的事件。
    • posted @ 2008-05-23 22:26 meetrice 阅读(307) 评论(0) 编辑
      首先,让我们回忆一下对于组件的讨论:
        1.只有配置了applyTo或renderTo属性才会在构建组件时立刻进行render方法的调用;
        2.如果是applyTo属性,则会对component的容器进行渲染;renderTo则是对component进行渲染;
       
        现在,让我们看一下render方法的实现:
      render : function(container, position)
      //如果还没有被渲染 并且beforerender方法返回值为true,则进行渲染,这样,确保了对于组件仅进行一次渲染; position参数指定了组件被插入容器的位置(即在position指定的元素前插入组件) 
      if(!this.rendered && this.fireEvent("beforerender"this!== false)
      //没有传入任何参数(即未指定容器container)并且设置了this.el,增配置this.container属性 
      if(!container && this.el)
        
      this.el = Ext.get(this.el); 
        container 
      = this.el.dom.parentNode; 
        
      this.allowDomMove = false
      }
       
      this.container = Ext.get(container); 
      //如果配置了ctCls,对container进行ctCls的渲染,ctCls(Container Class)是容器的渲染类名,cls(Class)是元素的渲染类名 
      if(this.ctCls)
        
      this.container.addClass(this.ctCls); 
      }
       
      this.rendered = true
      //设置position 
      if(position !== undefined)
        
      if(typeof position == 'number')
        position 
      = this.container.dom.childNodes[position]; 
        }
      else
        position 
      = Ext.getDom(position); 
        }
       
      }
       
      //进行onRender方法调用 
      this.onRender(this.container, position || null); 
      //如果设置了autoShow,则移除x-hidden和x-hide-hideMode(根据hideMode该属性可以配置为display,visibility,offsets三种属性),从这个方法可以看出,一搬来说,组件创建后缺省的模式为hidden或者none
      if(this.autoShow)
        
      this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]); 
      }
       
      //如果设置了cls,则对元素进行渲染 
      if(this.cls)
        
      this.el.addClass(this.cls); 
        
      delete this.cls; 
      }
       
      //如果设置了style,则对元素Style属性进行设置 
      if(this.style)
        
      this.el.applyStyles(this.style); 
        
      delete this.style; 
      }
       
      //触发fireEvent和AfterRender事件 
      this.fireEvent("render"this); 
      this.afterRender(this.container); 
      //如果设置了hidden和disabled则进行相应的处理 
      if(this.hidden)
        
      this.hide(); 
      }
       
      if(this.disabled)
        
      this.disable(); 
      }
       
      this.initStateEvents(); 
      }
       
      return this
      }
       


      onRender实现的方法如下:
      onRender : function(ct, position)
      //如果配置了autoEl属性,则根据autoEl属性生成el属性, 如果autoEl属性为字符串,则根据字符串生成元素;否则,则在autoEl指定的元素外包裹一层div元素 
      if(this.autoEl)
      if(typeof this.autoEl == 'string')
        
      this.el = document.createElement(this.autoEl); 
      }
      else
        
      var div = document.createElement('div'); 
        Ext.DomHelper.overwrite(div, 
      this.autoEl); 
        
      this.el = div.firstChild; 
      }
       
      }
       
      //把position元素插入到el元素前 
      if(this.el)
      this.el = Ext.get(this.el); 
      if(this.allowDomMove !== false)
        ct.dom.insertBefore(
      this.el.dom, position); 
      }
       
      }
       
      }
       
      posted @ 2008-05-23 22:25 meetrice 阅读(1319) 评论(0) 编辑
      在Ext2.0中,Component是一切Widget的父类,所有的Widget都继承与它,而他又继承自Observable,因此,它天生就具备了对于事件的处理能力。
      首先,让我们看一下它的构建器,它的构建器可以传入三种类型的对象: 对象(该对象的initailConfig属性为真正的配置对象;isAction属性决定了该参数是否是一个Ext.Action对象,如果是Ext.Action对象则注册Component对象)、Ext.Element对象和字符串对象。如果是Ext.element对象或是String对象,Component会在构建其对象中把他们转换为配置属性对象:
      Ext.Component = function(config)
      config 
      = config || {}
      if(config.initialConfig)
      if(config.isAction){   // 如果配置属性对象是Ext.action对象 
      this.baseAction = config; 
      }
       
      config 
      = config.initialConfig; // component cloning / action set up 
      }
      else if(config.tagName || config.dom || typeof config == "string")// element object 
      config = {applyTo: config, id: config.id || config}
      }
       
      /* 
      从以上的代码可以看出,Config对象的结够应该如下所示: 

      applyTo:
      id:, 
      initialConfig:{}, 
      isAction:boolean 

      */
       
      this.initialConfig = config; 
      Ext.apply(
      this, config); 

      Ext.ComponentMgr.register(
      this);//向ComponentMgr中注册自己 
      Ext.Component.superclass.constructor.call(this);//调用父类的构建器 
      //
      在Action中注册自己 
      if(this.baseAction)
      this.baseAction.addComponent(this); 
      }
       
      this.initComponent(); 

      // Component还注册了以下的事件,换句话说,所有的widget都支持以下的事件: 
      this.addEvents( 
      'disable'
      'enable'
      'beforeshow'
      'show'
      'beforehide'
      'hide'
      'beforerender'
      'render'
        
      'beforedestroy'
        
      'destroy'
        
      'beforestaterestore'
        
      'staterestore'
        
      'beforestatesave'
        
      'statesave' 
      ); 


      Component还提供了对Plugin的支持,在构建过程中,Component对插件逐一的进行调用:
      if(this.plugins)
      if(this.plugins instanceof Array)
        
      for(var i = 0, len = this.plugins.length; i < len; i++)
          
      this.plugins.init(this); 
        }
       
      }
      else
        
      this.plugins.init(this); 
      }
       
      }
       

      最后,如果Config对象中配置了applyTo属性则进行applyToMarkup处理,如果配置了renderTo属性则进行renderTo属性的渲染:
      if(this.applyTo)
      this.applyToMarkup(this.applyTo); 
      delete this.applyTo; 
      }
      else if(this.renderTo)
      this.render(this.renderTo); 
      delete this.renderTo; 
      }
       

      applyToMarkup方法实际上也是间接的调用了render方法,实际上,它是对applyTo对象的容器进行render方法的调用:
      applyToMarkup : function(el)
      this.allowDomMove = false
      this.el = Ext.get(el); 
      this.render(this.el.dom.parentNode); 
      }
       

      由以上的分析,我们可以得出如下的结论:
      1.如果Component的Config对象属性配置了renderTo和applyTo属性,则Component对象会在构建时立刻进行渲染;否则,渲染不会在构建时进行(这是处于性能的考虑)。
      2.配置renderTo和applyTo属性的区别如下:
        1)renderTo是对组件进行渲染,而applyTo是对组件的容器进行渲染;
        2)applyTo对组件进行了this.el属性的设置,而renderTo未进行任何设置;

      posted @ 2008-05-23 22:23 meetrice 阅读(529) 评论(0) 编辑
      Observable维护了一个events数组,并提供了更加方便的对于事件的封装和调用机制。同Event一样,它也提供了addListener、removeListener方法。它提供的addListenere方法使用起来更加方便,你可以通过json对象一次实现多个事件的绑定:
      foo.addListener(
      'click' : 
        fn: 
      this.onClick, 
        scope: 
      this
        delay: 
      100 
      }

      'mouseover' : 
        fn: 
      this.onMouseOver, 
        scope: 
      this 
      }

      'mouseout' : 
        fn: 
      this.onMouseOut, 
        scope: 
      this 
      }
       
      }


      如果你看一下源程序,你会发现,实际上,observable最终还是把事件绑定机制委托到Event对象上:
      addListener : function(eventName, fn, scope, o)
          
      //如果参数是一个json对象 
          if(typeof eventName == "object")
          o 
      = eventName; 
          
      for(var e in o)
            
      if(this.filterOptRe.test(e))
              
      continue
            }
       
            
      if(typeof o[e] == "function")
              
      // shared options 
              this.addListener(e, o[e], o.scope, o); 
            }
      else
              
      // individual options 
              this.addListener(e, o[e].fn, o[e].scope, o[e]); 
            }
       
          }
       
          
      return
        }
       
        o 
      = (!|| typeof o == "boolean"? {} : o; 
        eventName 
      = eventName.toLowerCase(); 
        
      var ce = this.events[eventName] || true
        
      if(typeof ce == "boolean")
          
      //事件不存在则新建一个Event对象并把它纳入event数组 
          ce = new Ext.util.Event(this, eventName); 
          
      this.events[eventName] = ce; 
        }
       
        
      //调用event的addListener方法 
        ce.addListener(fn, scope, o); 
      }
       
      除了支持addListener方法,Obserable还提供了一个addEvent方法,通过该方法,Observable可以绑定多个不包含处理句柄的Event对象:
       
      addEvents : function(o){
          
      if(!this.events){
              
      this.events = {};
          }

          
      if(typeof o == 'string'){
              
      for(var i = 0, a = arguments, v; v = a; i++){
                
      if(!this.events[a]){
                  o[a] 
      = true;
                }

              }

          }
      else{
              Ext.applyIf(
      this.events, o);
          }

        }
      ,


      为了方便使用,observable对addListener和removeListener提供了一个更加简洁的所写:on和un:
      Ext.util.Observable.prototype.on = Ext.util.Observable.prototype.addListener;
      Ext.util.Observable.prototype.un = Ext.util.Observable.prototype.removeListener;

      你可以通过suspendEvents和resumeEvents方法随时对于事件进行暂停和继续:
      suspendEvents : function()
        
      this.eventsSuspended = true
      }

      resumeEvents : 
      function()
        
      this.eventsSuspended = false
      }


      当然,通过fireEvent方法,你可以触发制定的事件:
      fireEvent : function()
        
      if(this.eventsSuspended !== true)
          
      //arguments[0]就是你需要触发的事件 
          var ce = this.events[arguments[0].toLowerCase()]; 
          
      if(typeof ce == "object")
            
      return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1)); 
          }
       
        }
       
        
      return true
      }



      Observable还通过capture和releaseCapture提供了对于事件处理函数的拦截机制:
      Ext.util.Observable.capture = function(o, fn, scope)
      o.fireEvent 
      = o.fireEvent.createInterceptor(fn, scope); 
      }

      Ext.util.Observable.releaseCapture 
      = function(o)
      o.fireEvent 
      = Ext.util.Observable.prototype.fireEvent; 
      }

      posted @ 2008-05-23 22:20 meetrice 阅读(2396) 评论(0) 编辑
       由于Ext2.0中所有的组件都是由Observable继承而来,理解Ext就需要先从Ext.util.Observable说起,而Observable是对Event对象进行管理,从而理解Observable必须首先从Ext.util.Event说起。
        Ext.util.Event是一个封装的非常精致的对象,但和你想象的不同,Event同任何的HTML DOM元素没有任何的关系(尽管Ext是处理HTML元素的),实际上,它是一个通用的事件及其事件的处理的对象。 也许有朋友要问,HTML Element本身已经支持了事件,为什么还要再重新设计一套Event机制呢?其实,基本上所有的javascript框架都会实现自己的Event机制,原因很多,但是至少有一点:HTML元素对于事件的处理是通过简单的单一绑定实现,也就是说,如果不进行任何的封装,你的事件只能唯一的绑定到一个事件处理句柄,举个例子:
        var e=document.getElementById("test");
        e.onclick=function(){alert("handle1")};
        e.onclick=function(){alert("handle2")};
        运行的结果你回发现,只会弹出一个"handle2"的alert框,因为第一个事件已经被第二个事件重载了。而使用Ext框架,你可以放心的解决这个问题,同一个事件可以依次被绑定到多个事件处理句柄上。
        Ext.util.Event对象构建器需要传入两个对象:obj(处理事件的缺省对象),name(事件名称)。在构建Event对象时,Event对象会同时构建一个事件的处理函数的数组:listeners,通过这个数组实现了一个事件的多个事件句柄函数的处理。
      Ext.util.Event = function(obj, name){
        this.name = name;
        this.obj = obj;
        this.listeners = [];
      };

      通过Event的fire方法就可以依次触发该数组中的处理函数。 实际上,fire方法在遍历listeners数组中的处理函数过程中,只要处理函数的返回值为false,则不再继续运行后续的处理函数。所以,可以通过检查fire方法的返回值得知事件处理函数是否完全被运行。 
        
      fire : function()
          
      var ls = this.listeners, scope, len = ls.length; 
          
      if(len > 0)
            
      this.firing = true;//通过firing可以保证多个事件处理函数不会并发运行 
            var args = Array.prototype.slice.call(arguments, 0);//slice方法可以有效的进行数组的克隆 
            for(var i = 0; i < len; i++)
              
      var l = ls; 
              
      //事件的处理,只要有一个处理函数返回false,整个事件处理就被停止 
              if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false)
                
      this.firing = false
                
      return false
              }
       
            }
       
            
      this.firing = false
          }
       
          
      return true
        }
       

        Event可以通过addListener、removeListener、clearListeners(移除所有的事件处理函数)方法对listeners进行管理。但是,Listener中保存的事件处理函数实际上并不是addListener传递的函数,实际上,addListener传入的方法通过createListener对事件的处理函数进行了封装,通过封装,实现了对通一个重复事件的的三种不同处理方式:delay(延迟运行)、single(移除Listener中的处理函数,仅运行当前的处理函数)、buffer(避免重复运行处理函数)。 
       
      createListener : function(fn, scope, o)
          o 
      = o || {}
          scope 
      = scope || this.obj; 
          
      var l = {fn: fn, scope: scope, options: o}
          
      var h = fn; 
          
      if(o.delay)
            h 
      = createDelayed(h, o, scope); 
          }
       
          
      if(o.single)
            h 
      = createSingle(h, this, fn, scope); 
          }
       
          
      if(o.buffer)
            h 
      = createBuffered(h, o, scope); 
          }
       
          l.fireFn 
      = h; 
          
      return l; 
        }
       


        
      var createBuffered = function(h, o, scope){
          
      var task = new Ext.util.DelayedTask();
          
      return function(){
              task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 
      0));
          }
      ;
        }
      ;
        
      var createSingle = function(h, e, fn, scope){
          
      return function(){
              e.removeListener(fn, scope);
              
      return h.apply(scope, arguments);
          }
      ;
        }
      ;
        
      var createDelayed = function(h, o, scope){
          
      return function(){
              
      var args = Array.prototype.slice.call(arguments, 0);
              setTimeout(
      function(){
                h.apply(scope, args);
              }
      , o.delay || 10);
          }
      ;
        }
      ;

      posted @ 2008-05-23 22:14 meetrice 阅读(777) 评论(0) 编辑
      Ext.tree.TreePanel
      树状控件,继承自panel


      config定义{
      animate : Boolean,
      containerScroll : Boolean,
      ddAppendOnly : String, /*很显然这是api的一个错误,treepanel.js中惟一用到它的地方是this.dropZone = new            Ext.tree.TreeDropZone(this, this.dropConfig || {
                     ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
                 })
          只有没有定义dropConfig才会影响ddconfig的appendOnly,原api说明是
          True if the tree should only allow append drops 只有当值为真时才允许以追加的方式接受拖曳*/
      ddGroup : String,   
      ddScroll : Boolean,
      dragConfig : Object,
      dropConfig : Object,
      enableDD : Boolean,
      enableDrag : Boolean,
      enableDrop : Boolean,    //以上参数更应该放在Ext.dd中学习
      hlColor : String,    //高亮颜色   
      hlDrop : Boolean    //曳入时高亮显示?
      lines : Boolean    //显示树形控件的前导线
      loader : Ext.tree.TreeLoader    //这是个重要的参数,用于方便的构建树形菜单,用于远程调用树状数据
      pathSeparator : String    //默径分隔符.默认为/
      rootVisible : Boolean //根可见?这是个有趣的属性,因为树只能有且仅有一个根,当我们需要两个或更多的"根"时就要用它了
      selModel : Boolean    /*选择模式,默认的是一个Ext.tree.DefaultSelectionModel实例,也可以是Ext.tree.MultiSelectionModel,如果你有兴趣,还可以自己定义,当然,它绝对不是一个布尔值
      另,虽然内置的两种选择方式都支持getSelectedNodes和clearSelections() 方法,但treenode中好象只用到的select/unSelecte/isSelected,如果自己继承写SelectionModel应该至少支持这三个方法
      */
      singleExpand : Boolean    //在所有的兄弟节点中只能有一个被展开

      属性
      dragZone : Ext.tree.TreeDragZone
      dropZone : Ext.tree.TreeDropZone
      root : Node    //最重要的也就是这个属性了

      方法
      TreePanel( Object config )
      构造

      collapseAll() : void
      expandAll() : void
      收起展开所有节点

      expandPath( String path, [String attr], [Function callback] ) : void
      由path找到节点,展开树到此节点

      getChecked( [String attribute], [TreeNode startNode] ) : Array
      返回一个包含所有选中节点的数组.或者所有选中节点的属性attribute组成的数组

      getEl() : Element
      返回当前TreePanel的容器对象

      getLoader() : Ext.tree.TreeLoader
      当前所使用的TreeLoader对象

      getNodeById( String id ) : Node
      由指定的节点id找到节点对象

      getRootNode() : Node
      得到根节点,同属性root

      getSelectionModel() : TreeSelectionModel
      得到选择模式

      getTreeEl() : Ext.Element
      返回当前tree下面的元素

      selectPath( String path, [String attr], [Function callback] ) : void
      由path选择指定的节点,它事实上调用的是expandPath用于展开节点对象

      setRootNode( Node node ) : Node
      设置根节点

      事件
      append : ( Tree tree, Node parent, Node node, Number index )
      beforeappend : ( Tree tree, Node parent, Node node )
      beforechildrenrendered : ( Node node )
      beforeclick : ( Node node, Ext.EventObject e )
      beforecollapsenode : ( Node node, Boolean deep, Boolean anim )
      beforeexpandnode : ( Node node, Boolean deep, Boolean anim )
      beforeinsert : ( Tree tree, Node parent, Node node, Node refNode )
      beforeload : ( Node node )
      beforemove : ( Tree tree, Node node, Node oldParent, Node newParent, Number index )
      beforenodedrop : ( Object dropEvent )
      beforeremove : ( Tree tree, Node parent, Node node )
      checkchange : ( Node this, Boolean checked )
      click : ( Node node, Ext.EventObject e )
      collapsenode : ( Node node )
      contextmenu : ( Node node, Ext.EventObject e )
      dblclick : ( Node node, Ext.EventObject e )
      disabledchange : ( Node node, Boolean disabled )
      dragdrop : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, DD dd, event e )
      enddrag : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, event e )
      expandnode : ( Node node )
      insert : ( Tree tree, Node parent, Node node, Node refNode )]
      load : ( Node node )
      move : ( Tree tree, Node node, Node oldParent, Node newParent, Number
      nodedragover : ( Object dragOverEvent )
      nodedrop : ( Object dropEvent )
      remove : ( Tree tree, Node parent, Node node )
      startdrag : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, event e )
      textchange : ( Node node, String text, String oldText )


      Ext.tree.TreeNode
      树状控件的节点类,继承自Ext.data.Node

      config{
          allowChildren : Boolean
          allowDrag : Boolean
          allowDrop : Boolean
          checked : Boolean        //无论设为真还是假都会在前面有个选择框,默认未设置
          cls : String
          disabled : Boolean
          draggable : Boolean
          expandable : Boolean
          expanded : Boolean       
          href : String            //超链接
          hrefTarget : String
          icon : String            //图标
          iconCls : String       
          isTarget : Boolean        //是拖曳的目标?
          qtip : String            //提示
          qtipCfg : String        //
          singleClickExpand : Boolean    //单击展开
          text : String        //文本内容
          uiProvider : Function    //默认Ext.tree.TreeNodeUI,如果想自己提供ui可以自已再继承Ext.tree.TreeNodeUI
      }

      属性
      disabled : Boolean   
      text : String
      ui : TreeNodeUI    //此属性只读.参见uiProvider

      方法
      TreeNode( Object/String attributes )
      构造

      collapse( [Boolean deep], [Boolean anim] ) : void
      收起本节点

      collapseChildNodes( [Boolean deep] ) : void
      收起子节点

      disable() : void
      enable() : void
      禁止允许

      ensureVisible() : void
      确保所有的父节点都是展开的

      expand( [Boolean deep], [Boolean anim], [Function callback] ) : void
      展开到当前节点

      expand( [Boolean deep], [Boolean anim], [Function callback] ) : void
      展开本节点

      expandChildNodes( [Boolean deep] ) : void
      展开所有的子节点

      getUI() : TreeNodeUI
      返回ui属性

      isExpanded() : Boolean
      当前节点是否展开

      isSelected() : Boolean
      当前节点是否选择

      select() : void
      选择当前节点

      setText( String text ) : void
      设置当前节点的文本

      toggle() : void
      在展开或收起状态间切换

      unselect() : void
      取消选择

      事件
      beforechildrenrendered : ( Node this )
      beforeclick : ( Node this, Ext.EventObject e )
      beforecollapse : ( Node this, Boolean deep, Boolean anim )
      beforeexpand : ( Node this, Boolean deep, Boolean anim )
      checkchange : ( Node this, Boolean checked )
      click : ( Node this, Ext.EventObject e )
      collapse : ( Node this )
      contextmenu : ( Node this, Ext.EventObject e )
      dblclick : ( Node this, Ext.EventObject e )
      disabledchange : ( Node this, Boolean disabled )
      expand : ( Node this )
      textchange : ( Node this, String text, String oldText )


      Ext.tree.AsyncTreeNode
      继承自Ext.tree.TreeNode,支持异步创建,很显然除了多个loader与TreeNode没什么区别

      config{
       loader : TreeLoader   
      }
      属性
      loader : TreeLoader

      方法
      AsyncTreeNode( Object/String attributes )
      isLoaded() : Boolean
      isLoading() : Boolean
      reload( Function callback ) : void

      事件
      beforeload : ( Node this )
      load : ( Node this )


      Ext.tree.TreeNodeUI
      为节点输出而设计,如果想创建自己的ui,应该继承此类
      方法
      addClass( String/Array className ) : void
      增加样式类

      getAnchor() : HtmlElement
      返回<a>元素

      getIconEl() : HtmlElement
      返回<img>元素

      getTextEl() : HtmlNode
      返回文本节点
      hide() : void
      隐藏
      isChecked() : Boolean
      选中?

      removeClass( String/Array className ) : void
      移除样式
      show() : void
      显示

      toggleCheck( Boolean (optional) ) : void
      切换选中状态


      Ext.tree.RootTreeNodeUI
      api上说它继承自object,事实上treenodeui它中继承自Ext.tree.TreeNodeUI,也只有这样才合理,用于输出根节点


      Ext.tree.TreeLoader
      用于远程读取树状数据来构造TreeNode的子节点

      config{
          baseAttrs : Object    //构造子节点的基础属性
          baseParams : Object    //请求url的传入参数
          clearOnLoad : Boolean    //重新载入前先清空子节点
          dataUrl : String        //远程请求时的url
          preloadChildren : Boolean    //节点第一次载入时递归的载入所有子孙节点的children属性
          uiProviders : Object    //ui提供者
          url : String    //等同于dataUrl
       }


      方法
      TreeLoader( Object config )
      构造
      createNode() : void
      创建节点,treeloader.js中定义的是createNode : function(attr),传入的应该是一个定制的节点

      load( Ext.tree.TreeNode node, Function callback ) : void
      为node载入子节点

      事件
      beforeload : ( Object This, Object node, Object callback )
      load : ( Object This, Object node, Object response )
      loadexception : ( Object This, Object node, Object response )


      Ext.tree.TreeSorter
      排序
      config{
          caseSensitive : Boolean//大小写敏感,默认为false
          dir : String    //正序还是倒序,可选asc/desc.默认asc
          folderSort : Boolean //叶节点排在非叶节点之下 ,默认为真
          leafAttr : String    //在folderSort中排序时的使用的属性,默认为leaf
          property : String    //用于排序的属性.默认为text
          sortType : Function    //可以通过特定的sortType先转换再排序
      }

      方法
      TreeSorter( TreePanel tree, Object config )
      构造

      Ext.tree.TreeFilter
      过滤器
      clear() : void
      清除当前过滤器

      filter( String/RegExp value, [String attr], [TreeNode startNode] ) : void

      filterBy( Function fn, [Object scope] ) : void
      使用过滤器,但正如api中所说的,这是个实验性的数,还有很多不足,基本上很难真的作用
       

       惯例来个小示例
       Ext.onReady(function(){
          
      //建立树
          var tree=new Ext.tree.TreePanel({
              el:Ext.getBody(),
              autoScroll:
      true,
              animate:
      true,
              height:
      200,
              enableDD:
      true,
              containerScroll: 
      true
          }
      );
         
          
      //建立根
           var root = new Ext.tree.TreeNode({
              text: 
      'Ext JS',
              draggable:
      false,
              id:
      'root'
          }
      );
          
      //设置根
          tree.setRootNode(root);
          tree.render();
         
          
      //增加子节点
          root.appendChild(new Ext.tree.TreeNode({
              text: 
      'csdn',
              href:
      'http://www.csdn.net',
              id:
      'node_csdn'
          }
      ));
         
          root.appendChild(
      new Ext.tree.TreeNode({
              text: 
      'duduw',
              href:
      'http://www.duduw.com',
              id:
      'duduw_Node'
          }
      ));
         
          
      //设置属性
          tree.root.attributes.description='这是根节点';
          
      //getNodeById
          tree.getNodeById('duduw_Node').attributes.description='这是叶节点';
          
      //选择第一个子节点
          tree.selectPath('/root/node_csdn');
          
      //事件
          tree.on('click',function(node,e){
              e.stopEvent();
              
      if(node.attributes.description){
                  Ext.MessageBox.show(
      {title:'您选择了',
                      msg:String.format(
      "description:{0}<br/>href:{1}",node.attributes.description,node.attributes.href)
                  }
      );
              }

          }
      );
         
       }
      ); 
      posted @ 2008-05-23 21:23 meetrice 阅读(919) 评论(0) 编辑
      posted @ 2008-05-23 21:22 meetrice 阅读(542) 评论(1) 编辑
      Ext.grid.ColumnModel
      用于定义Grid的列
      用例
      var colModel = new Ext.grid.ColumnModel([
          {header: "Ticker", width: 60, sortable: true},
          {header: "Company Name", width: 150, sortable: true}
          ]);


      回到ColumnModel,它的构造参数是一个config组成的数组,其中config定义为{
          align : String    //css中的对齐方式
          dataIndex : String    //要绑定的Store之Record字段名
          fixed : Boolean    //如果为真列宽不能被改变
          header : String    //头部显示的名称
          hidden : Boolean    //隐藏本列
          id : String    //主要用于样式选择,如果已定义此属性,那么列所在的单元格会定义class为 x-grid-td-id
          renderer : Function    //可以使用这个构造参数格式化数据
          resizable : Boolean    //可调节尺寸
          sortable : Boolean    // 可排序
          width : Number    //宽度
      }
      另外虽然未经声明,但config事实上支持editor:Ext.form.Field属性,这点会在Ext.grid.EditorGridPanel中看到,另外为了扩展grid的表现,我们通常也需要自定义列,顺便提一个有趣的列,Ext.grid.RowNumberer,这是Ext为我们扩展好的一个简单列,它的构造很简单,也没有其它的方法和属性,Ext.grid.RowNumberer({ header : String, sortable : Boolean, width : Number})如果使用它,上例可改为
      var colModel = new Ext.grid.ColumnModel([
          new Ext.grid.RowNumberer(),
          {header: "Ticker", width: 60, sortable: true},
          {header: "Company Name", width: 150, sortable: true}
          ]);
      属性
      defaultSortable : Boolean    //默认可排序
      defaultWidth : Number    //默认的宽度
      setConfig : Object    //返回构造时的config参数

      方法
       ColumnModel( Object config )
       构造

      getCellEditor( Number colIndex, Number rowIndex ) : Object
      得到指定行列的编辑者
      getColumnById( String id ) : Object
      得到指定id的列对象
      getColumnCount() : Number
      得到列数
      getColumnHeader( Number col ) : String
      得到列头部文本
      getColumnId( Number index ) : String
      得到列id
      getColumnTooltip( Number col ) : String
      得到列提示
      getColumnWidth( Number col ) : Number
      列宽
      getColumnsBy( Function fn, [Object scope] ) : Array
      通过fn找到指定的列
      getDataIndex( Number col ) : Number
      得到指定列的数据绑定对象在store中的序号
      getIndexById( String id ) : Number
      通过id找序号
      getRenderer( Number col ) : Function
      得到绘制器
      getTotalWidth( Boolean includeHidden ) : Number
      总的宽度
      hasListener( String eventName ) : Boolean
      有事件侦听者?
      isCellEditable( Number colIndex, Number rowIndex ) : Boolean
      指定行列可编辑?
      isFixed() : void
      应该返回Boolean,充满?
      isHidden( Number colIndex ) : Boolean
      指定列隐藏?
      isResizable() : Boolean
      可重写义大小
      isSortable( Number col ) : Boolean
      可排序?
      setColumnHeader( Number col, String header ) : void
      设置指定列列头
      setColumnTooltip( Number col, String tooltip ) : void
      设置指定列提示
      setColumnWidth( Number col, Number width ) : void
      设置指定列宽度
      setConfig( Array config ) : void
      重设config
      setDataIndex( Number col, Number dataIndex ) : void
      设置指定列的数据源
      setEditable( Number col, Boolean editable ) : void
      设置指定列是否可编辑
      setEditor( Number col, Object editor ) : void
      为指定列设置编辑器
      setHidden( Number colIndex, Boolean hidden ) : void
      设置指定列隐藏
      setRenderer( Number col, Function fn ) : void
      为指定列设置输出方法


      事件
      columnmoved : ( ColumnModel this, Number oldIndex, Number newIndex )
      configchanged : ( ColumnModel this )
      headerchange : ( ColumnModel this, Number columnIndex, String newText )
      hiddenchange : ( ColumnModel this, Number columnIndex, Boolean hidden )
      widthchange : ( ColumnModel this, Number columnIndex, Number newWidth )


      Ext.grid.PropertyColumnModel
      继承自Ext.grid.ColumnModel,专为Ext.grid.PropertyGrid而设计,构造有点不同,不过这个api文档不知道谁写的,ext2中好象没有grid了,
      PropertyColumnModel( Ext.grid.Grid grid, Object source )


      Ext.grid.GridView
      为GridPanel提供视图支持
      config{
          autoFill : Boolean
          enableRowBody : Boolean
          forceFit : Boolean
      }

      属性
      columnsText : String    //列文本
      scrollOffset : Number    //滚动步行
      sortAscText : String    //正序文本
      sortClasses : Array    //正序和倒序时头部列使用的样式,默认为["sort-asc", "sort-desc"]
      sortDescText : String    //倒序文本


      方法
      GridView( Object config )
      构造
      focusCell( Number row, Number col ) : void
      指定第row行第col列得到焦点
      focusRow( Number row ) : void
      选中第row行
      getCell( Number row, Number col ) : HtmlElement
      得到指定行列的htmlelement对象
      getHeaderCell( Number index ) : HtmlElement
      得到指定列的表单头对象
      getRow( Number index ) : HtmlElement
      得到指定行的htmlelement对象
      getRowClass( Record record, Number index, Object rowParams, Store ds ) : void
      //得到指定行的样式?郁闷的是没有能在GridView.js中找到此方法的定义
      refresh( [Boolean headersToo] ) : void
      涮新显示
      scrollToTop() : void
      滚动到头部

      Ext.grid.GroupingView
      继承自Ext.grid.GridView,用于数据分组 ,应用于
      config{
      emptyGroupText : String        //空的分组显示文本
      enableGroupingMenu : Boolean    //允许分组菜单
      enableNoGroups : Boolean    //允许分组/不分组显示
      groupTextTpl : String        //这是个模板,分组项的内容依此显示,语法参见模板,
      hideGroupedColumn : Boolean    //隐藏分组列
      startCollapsed : Boolean    //开始时收起,默认为假
      }
      另外虽然没有在api中说明,但groupByText和showGroupsText属性也是可以在config中指定的
      方法
      GroupingView( Object config )
      构造
      getGroupId( String value ) : void
      取得指定值的分组id,为toggleGroup而准备的方法
      toggleAllGroups( [Boolean expanded] ) : void
      收起或展开所有的分组
      toggleGroup( String groupId, [Boolean expanded] ) : void
      展开或收起指定的分组,例grid.view.toggleGroup(grid.view.getGroupId('Horticulturalist'));会展开或收起分组字段值为'Horticulturalist'的分组




       
        Ext.onReady(function(){
                  
      //定义数组
              var arr=[ ['Bill''Gardener'], [ 'Ben''Horticulturalist'],['''Gardener'],['''Gardener'],[ '''Horticulturalist'] ];
              
      var reader = new Ext.data.ArrayReader(
             
                 
      {},
              
      //定义数组到record的映射关系
                 [
                  
      {name: 'name'},        
                  
      {name: 'occupation', mapping: 1}   
                 ]
              );
              
      //生成元数据
               var store=new Ext.data.Store({
                      reader:reader
                  }
      );
              store.loadData(arr);
             
              
      //现在配置列信息   
              var col=new Ext.grid.ColumnModel([
                  
      new Ext.grid.RowNumberer({header:'序号',width:30}),
                  
      {header:'姓名',sortable: true,dataIndex:'name'},
                  
      {header:'职业',sortable: true,dataIndex:'occupation'}
              ]);
             
              
      //配置视图信息
              var view=new Ext.grid.GridView({forceFit:true,sortAscText :'正序', sortDescText :'倒序'});
              view.columnsText
      ='列显示/隐藏';

              
      //现在我们有一个可用的grid了,别骄傲这只是第一步       
              var grid=new Ext.grid.GridPanel({
                  el:Ext.getBody(),
                  height:
      200,
                  width:
      400,
                  store:store,
                  cm:col,
                  view:view
                  }
      );   
                 
              grid.render();
             
             
                  
      //现在我们需要一个GroupingStore
               var gstore=new Ext.data.GroupingStore({
                reader:reader,
                groupField:
      'name',
                groupOnSort:
      true,
                sortInfo:
      {field: 'occupation', direction: "ASC"} //使用GroupingStore时必须指定sortInfo信息
             }
      );
             gstore.loadData(arr);
            
                    
              
      //扩展一下我们的grid,让他能分组当然会更酷一点    
              var ggrid = new Ext.grid.GridPanel({
                  ds: gstore,
                  cm:col,
                  view: 
      new Ext.grid.GroupingView({
                      forceFit:
      true,
                      sortAscText :
      '正序',
                      sortDescText :
      '倒序',
                      columnsText:
      '列显示/隐藏',
                      groupByText:
      '依本列分组',
                      showGroupsText:
      '分组显示',
                      groupTextTpl: 
      '{text} ({[values.rs.length]} 条记录)'
                  }
      ),
                  frame:
      true,
                  width: 
      400,
                  height: 
      300,
                  collapsible: 
      true,
                  animCollapse: 
      false,
                  renderTo:Ext.getBody()
             }
      );   
             
             
              }
      ); 
      posted @ 2008-05-23 21:22 meetrice 阅读(837) 评论(0) 编辑
      Ext.tree.TreePanel
      树状控件,继承自panel


      config定义{
      animate : Boolean,
      containerScroll : Boolean,
      ddAppendOnly : String, /*很显然这是api的一个错误,treepanel.js中惟一用到它的地方是this.dropZone = new            Ext.tree.TreeDropZone(this, this.dropConfig || {
                     ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
                 })
          只有没有定义dropConfig才会影响ddconfig的appendOnly,原api说明是
          True if the tree should only allow append drops 只有当值为真时才允许以追加的方式接受拖曳*/
      ddGroup : String,   
      ddScroll : Boolean,
      dragConfig : Object,
      dropConfig : Object,
      enableDD : Boolean,
      enableDrag : Boolean,
      enableDrop : Boolean,    //以上参数更应该放在Ext.dd中学习
      hlColor : String,    //高亮颜色   
      hlDrop : Boolean    //曳入时高亮显示?
      lines : Boolean    //显示树形控件的前导线
      loader : Ext.tree.TreeLoader    //这是个重要的参数,用于方便的构建树形菜单,用于远程调用树状数据
      pathSeparator : String    //默径分隔符.默认为/
      rootVisible : Boolean //根可见?这是个有趣的属性,因为树只能有且仅有一个根,当我们需要两个或更多的"根"时就要用它了
      selModel : Boolean    /*选择模式,默认的是一个Ext.tree.DefaultSelectionModel实例,也可以是Ext.tree.MultiSelectionModel,如果你有兴趣,还可以自己定义,当然,它绝对不是一个布尔值
      另,虽然内置的两种选择方式都支持getSelectedNodes和clearSelections() 方法,但treenode中好象只用到的select/unSelecte/isSelected,如果自己继承写SelectionModel应该至少支持这三个方法
      */
      singleExpand : Boolean    //在所有的兄弟节点中只能有一个被展开

      属性
      dragZone : Ext.tree.TreeDragZone
      dropZone : Ext.tree.TreeDropZone
      root : Node    //最重要的也就是这个属性了

      方法
      TreePanel( Object config )
      构造

      collapseAll() : void
      expandAll() : void
      收起展开所有节点

      expandPath( String path, [String attr], [Function callback] ) : void
      由path找到节点,展开树到此节点

      getChecked( [String attribute], [TreeNode startNode] ) : Array
      返回一个包含所有选中节点的数组.或者所有选中节点的属性attribute组成的数组

      getEl() : Element
      返回当前TreePanel的容器对象

      getLoader() : Ext.tree.TreeLoader
      当前所使用的TreeLoader对象

      getNodeById( String id ) : Node
      由指定的节点id找到节点对象

      getRootNode() : Node
      得到根节点,同属性root

      getSelectionModel() : TreeSelectionModel
      得到选择模式

      getTreeEl() : Ext.Element
      返回当前tree下面的元素

      selectPath( String path, [String attr], [Function callback] ) : void
      由path选择指定的节点,它事实上调用的是expandPath用于展开节点对象

      setRootNode( Node node ) : Node
      设置根节点

      事件
      append : ( Tree tree, Node parent, Node node, Number index )
      beforeappend : ( Tree tree, Node parent, Node node )
      beforechildrenrendered : ( Node node )
      beforeclick : ( Node node, Ext.EventObject e )
      beforecollapsenode : ( Node node, Boolean deep, Boolean anim )
      beforeexpandnode : ( Node node, Boolean deep, Boolean anim )
      beforeinsert : ( Tree tree, Node parent, Node node, Node refNode )
      beforeload : ( Node node )
      beforemove : ( Tree tree, Node node, Node oldParent, Node newParent, Number index )
      beforenodedrop : ( Object dropEvent )
      beforeremove : ( Tree tree, Node parent, Node node )
      checkchange : ( Node this, Boolean checked )
      click : ( Node node, Ext.EventObject e )
      collapsenode : ( Node node )
      contextmenu : ( Node node, Ext.EventObject e )
      dblclick : ( Node node, Ext.EventObject e )
      disabledchange : ( Node node, Boolean disabled )
      dragdrop : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, DD dd, event e )
      enddrag : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, event e )
      expandnode : ( Node node )
      insert : ( Tree tree, Node parent, Node node, Node refNode )]
      load : ( Node node )
      move : ( Tree tree, Node node, Node oldParent, Node newParent, Number
      nodedragover : ( Object dragOverEvent )
      nodedrop : ( Object dropEvent )
      remove : ( Tree tree, Node parent, Node node )
      startdrag : ( Ext.tree.TreePanel this, Ext.tree.TreeNode node, event e )
      textchange : ( Node node, String text, String oldText )


      Ext.tree.TreeNode
      树状控件的节点类,继承自Ext.data.Node

      config{
          allowChildren : Boolean
          allowDrag : Boolean
          allowDrop : Boolean
          checked : Boolean        //无论设为真还是假都会在前面有个选择框,默认未设置
          cls : String
          disabled : Boolean
          draggable : Boolean
          expandable : Boolean
          expanded : Boolean       
          href : String            //超链接
          hrefTarget : String
          icon : String            //图标
          iconCls : String       
          isTarget : Boolean        //是拖曳的目标?
          qtip : String            //提示
          qtipCfg : String        //
          singleClickExpand : Boolean    //单击展开
          text : String        //文本内容
          uiProvider : Function    //默认Ext.tree.TreeNodeUI,如果想自己提供ui可以自已再继承Ext.tree.TreeNodeUI
      }

      属性
      disabled : Boolean   
      text : String
      ui : TreeNodeUI    //此属性只读.参见uiProvider

      方法
      TreeNode( Object/String attributes )
      构造

      collapse( [Boolean deep], [Boolean anim] ) : void
      收起本节点

      collapseChildNodes( [Boolean deep] ) : void
      收起子节点

      disable() : void
      enable() : void
      禁止允许

      ensureVisible() : void
      确保所有的父节点都是展开的

      expand( [Boolean deep], [Boolean anim], [Function callback] ) : void
      展开到当前节点

      expand( [Boolean deep], [Boolean anim], [Function callback] ) : void
      展开本节点

      expandChildNodes( [Boolean deep] ) : void
      展开所有的子节点

      getUI() : TreeNodeUI
      返回ui属性

      isExpanded() : Boolean
      当前节点是否展开

      isSelected() : Boolean
      当前节点是否选择

      select() : void
      选择当前节点

      setText( String text ) : void
      设置当前节点的文本

      toggle() : void
      在展开或收起状态间切换

      unselect() : void
      取消选择

      事件
      beforechildrenrendered : ( Node this )
      beforeclick : ( Node this, Ext.EventObject e )
      beforecollapse : ( Node this, Boolean deep, Boolean anim )
      beforeexpand : ( Node this, Boolean deep, Boolean anim )
      checkchange : ( Node this, Boolean checked )
      click : ( Node this, Ext.EventObject e )
      collapse : ( Node this )
      contextmenu : ( Node this, Ext.EventObject e )
      dblclick : ( Node this, Ext.EventObject e )
      disabledchange : ( Node this, Boolean disabled )
      expand : ( Node this )
      textchange : ( Node this, String text, String oldText )


      Ext.tree.AsyncTreeNode
      继承自Ext.tree.TreeNode,支持异步创建,很显然除了多个loader与TreeNode没什么区别

      config{
       loader : TreeLoader   
      }
      属性
      loader : TreeLoader

      方法
      AsyncTreeNode( Object/String attributes )
      isLoaded() : Boolean
      isLoading() : Boolean
      reload( Function callback ) : void

      事件
      beforeload : ( Node this )
      load : ( Node this )


      Ext.tree.TreeNodeUI
      为节点输出而设计,如果想创建自己的ui,应该继承此类
      方法
      addClass( String/Array className ) : void
      增加样式类

      getAnchor() : HtmlElement
      返回<a>元素

      getIconEl() : HtmlElement
      返回<img>元素

      getTextEl() : HtmlNode
      返回文本节点
      hide() : void
      隐藏
      isChecked() : Boolean
      选中?

      removeClass( String/Array className ) : void
      移除样式
      show() : void
      显示

      toggleCheck( Boolean (optional) ) : void
      切换选中状态


      Ext.tree.RootTreeNodeUI
      api上说它继承自object,事实上treenodeui它中继承自Ext.tree.TreeNodeUI,也只有这样才合理,用于输出根节点


      Ext.tree.TreeLoader
      用于远程读取树状数据来构造TreeNode的子节点

      config{
          baseAttrs : Object    //构造子节点的基础属性
          baseParams : Object    //请求url的传入参数
          clearOnLoad : Boolean    //重新载入前先清空子节点
          dataUrl : String        //远程请求时的url
          preloadChildren : Boolean    //节点第一次载入时递归的载入所有子孙节点的children属性
          uiProviders : Object    //ui提供者
          url : String    //等同于dataUrl
       }


      方法
      TreeLoader( Object config )
      构造
      createNode() : void
      创建节点,treeloader.js中定义的是createNode : function(attr),传入的应该是一个定制的节点

      load( Ext.tree.TreeNode node, Function callback ) : void
      为node载入子节点

      事件
      beforeload : ( Object This, Object node, Object callback )
      load : ( Object This, Object node, Object response )
      loadexception : ( Object This, Object node, Object response )


      Ext.tree.TreeSorter
      排序
      config{
          caseSensitive : Boolean//大小写敏感,默认为false
          dir : String    //正序还是倒序,可选asc/desc.默认asc
          folderSort : Boolean //叶节点排在非叶节点之下 ,默认为真
          leafAttr : String    //在folderSort中排序时的使用的属性,默认为leaf
          property : String    //用于排序的属性.默认为text
          sortType : Function    //可以通过特定的sortType先转换再排序
      }

      方法
      TreeSorter( TreePanel tree, Object config )
      构造

      Ext.tree.TreeFilter
      过滤器
      clear() : void
      清除当前过滤器

      filter( String/RegExp value, [String attr], [TreeNode startNode] ) : void

      filterBy( Function fn, [Object scope] ) : void
      使用过滤器,但正如api中所说的,这是个实验性的数,还有很多不足,基本上很难真的作用
       

       惯例来个小示例
       Ext.onReady(function(){
          
      //建立树
          var tree=new Ext.tree.TreePanel({
              el:Ext.getBody(),
              autoScroll:
      true,
              animate:
      true,
              height:
      200,
              enableDD:
      true,
              containerScroll: 
      true
          }
      );
         
          
      //建立根
           var root = new Ext.tree.TreeNode({
              text: 
      'Ext JS',
              draggable:
      false,
              id:
      'root'
          }
      );
          
      //设置根
          tree.setRootNode(root);
          tree.render();
         
          
      //增加子节点
          root.appendChild(new Ext.tree.TreeNode({
              text: 
      'csdn',
              href:
      'http://www.csdn.net',
              id:
      'node_csdn'
          }
      ));
         
          root.appendChild(
      new Ext.tree.TreeNode({
              text: 
      'duduw',
              href:
      'http://www.duduw.com',
              id:
      'duduw_Node'
          }
      ));
         
          
      //设置属性
          tree.root.attributes.description='这是根节点';
          
      //getNodeById
          tree.getNodeById('duduw_Node').attributes.description='这是叶节点';
          
      //选择第一个子节点
          tree.selectPath('/root/node_csdn');
          
      //事件
          tree.on('click',function(node,e){
              e.stopEvent();
              
      if(node.attributes.description){
                  Ext.MessageBox.show(
      {title:'您选择了',
                      msg:String.format(
      "description:{0}<br/>href:{1}",node.attributes.description,node.attributes.href)
                  }
      );
              }

          }
      );
         
       }
      ); 
      posted @ 2008-05-23 21:21 meetrice 阅读(1178) 评论(0) 编辑
      posted @ 2008-05-23 21:21 meetrice 阅读(157) 评论(0) 编辑
      Ext.Toolbar
      工具栏,使用起来很简单,add已准备好的元素就行

      方法
      Toolbar( Object/Array config )
      构造

      add( Mixed arg1, Mixed arg2, Mixed etc. ) : void
      增加元素
      可以是
      1:Ext.Toolbar.Button            相当于addButton
      2:HtmlElement                相当于addElement
      3:Field                    相当于addField
      4:Item                    相当于addItem
      5:String                相当于addText
      6:'separator'或'-'            相当于addSeparator
      7:''                    相当于addSpacer
      8:'->'                    相当于addFill

      addButton( Object/Array config ) : Ext.Toolbar.Button/Array
      添加Ext.Toolbar.Button/SplitButton对象,其实因为Ext.Toolbar.Button和Ext.Button用起来没什么区别,而且Toolbar两者都支持,我实验时没发现使用上有什么不同

      addDom( Object config ) : Ext.Toolbar.Item
      添加DOM节点

      addElement( Mixed el ) : Ext.Toolbar.Item
      添加Element对象
      addField( Ext.form.Field field ) : Ext.ToolbarItem
      添加Ext.form.Field对象

      addFill() : Ext.Toolbar.Fill
      添加一个撑满工具条的空白元素

      addItem( Ext.Toolbar.Item item ) : Ext.Toolbar.Item
      添回Ext.Toolbar.Item对象

      addSeparator() : Ext.Toolbar.Item
      添加一个分隔元素,相当于addItem(new Ext.Toolbar.Separator());

      addSpacer() : Ext.Toolbar.Spacer
      添加一个空白元素,相当于addItem(new Ext.Toolbar.Spacer());

      addText( String text ) : Ext.Toolbar.Item
      添加文本元素,相当于addItem(new Ext.Toolbar.TextItem(text));

      insertButton( Number index, Object/Ext.Toolbar.Item/Ext.Toolbar.Button button ) : Ext.Toolbar.Button/Item
      在第index个元素之前插入button对象

      Ext.Toolbar.Item
      工具栏元素基类

      Toolbar.Item( HTMLElement el )
      构造

      destroy() : void
      销毁

      disable() : void
      enable() : void
      可用/禁用

      focus() : void
      得到焦点 

      getEl() : HTMLElement
      得到当前DOM对象

      setVisible( Boolean visible ) : void
      show() : void
      hide() : void
      显示隐藏

      Ext.Toolbar.Separator
      继承自item,工具栏分隔符

      Ext.Toolbar.Spacer
      继承自item,工具栏空白元素

      Ext.Toolbar.TextItem
      继承自item,工具栏文本元素

      Ext.Toolbar.Fill
      继承自Spacer,工具栏空白元素,撑满工具栏

      简单的示例
      var tb = new Ext.Toolbar({width:400});
      //在add之前先render,必要,不然会报错//在add之前先render,必要
      tb.render(Ext.getBody());


      tb.addText(
      '请选择时间');
      tb.add( 
      new Ext.form.DateField(//DateField
          fieldLabel:'DateField',
          format:
      'Y-m-d',
          disabledDays:[
      0,6]
          }
      )
      );
      tb.addButton(
          
      new Ext.Toolbar.Button({
          text:
      'button',
          handler:
      function(item){
              Ext.MessageBox.alert(
      "toolbar","您点击了"+item.text)
          }

          }
      )
      );
      tb.addSpacer();
      tb.addSeparator();
      tb.addFill();
      tb.add(
      new Ext.SplitButton({
          handler: 
      function(item){
              Ext.MessageBox.alert(
      "点击事件",String.format("您选择了{0}",item.text));
              }
      ,
          arrowTooltip : 
      "更多",
          text:
      '按我',
          menu:
      new Ext.menu.Menu({
              id: 
      'mainMenu',
             
              items: [
              
      {
                  text: 
      '菜单项1'
              }
      ,
              
      {
                  text: 
      '菜单项2'
              }
      ]
          }
      )
          }
      )
      );
      tb.add(
      '右边结束');

      posted @ 2008-05-23 21:20 meetrice 阅读(396) 评论(0) 编辑
      posted @ 2008-05-23 21:19 meetrice 阅读(330) 评论(0) 编辑
      Ext.form.BasicForm
      对应一个dom中的form,默认是用ajax提交的,如果的确想回传,可以使用如下方式
      var myForm = new Ext.form.BasicForm("form-el-id", {
              onSubmit: Ext.emptyFn,
              submit: function() {
                  this.getEl().dom.submit();
              }
          });

      方法:
       BasicForm( Mixed el, Object config )
      其中config配置为
      {
       baseParams : Object,    //请求时的附加参数,格式为{id: '123', foo: 'bar'}
       errorReader : DataReader,    //提交时发生验证错误,这个dataReader将会被使用
       fileUpload : Boolean,    //支持文件上传
       method : String,    //GET或者POST
       reader : DataReader,    //load时使用的数据读取器
       timeout : Number,    //超时时间
       trackResetOnLoad : Boolean,//支持使用reset方法恢复原始值
       url : String    //form要提交的url地址
      }

      add( Field field1, [Field field2], [Field etc] ) : BasicForm
      增加字段field1,field2,etc


      applyIfToFields( Object values ) : BasicForm
      applyToFields( Object values ) : BasicForm
      用传入的values呼叫Ext.applyIf/apply 方法

      clearInvalid() : BasicForm
      清除当前basicform中所有的非法信息

      doAction( String/Object actionName, [Object options] ) : BasicForm
      执行预定义的动作actionName,actionName类似"submit","load",也可以是自定义的动作的名字或一个Ext.form.Action的实例,options类似如下对象{
      url               :String,
      method            :String,          
      params            :String/Object,  
      success           :Function,
      failure           :Function,
      clientValidation  :Boolean        
      }

      findField( String id ) : Field
      在当前form中查找id/dataindex/name等于传入的id的field对象

      getEl() : Ext.Element
      得到当前form对象的element对象


      getValues( Boolean asString ) : Object
      得到当前form的fields {name:value,name:values}json对象,如果有同名多值,value将是一个数组

      isDirty() : Boolean
      从初始载入后,是否有field被修改过

      isValid() : Boolean
      客户端验证成功?

      load( Object options ) : BasicForm
      等效于doAction('load',options);

      loadRecord( Record record ) : BasicForm
      从一个record对象取值到当前basicform

      markInvalid( Array/Object errors ) : BasicForm
      标志非法,[{id:'fieldId', msg:'The message'},...]这样格式的数组或者{id: msg, id2: msg2}格式的对象

      remove( Field field ) : BasicForm
      从basicform中移除field

      render() : BasicForm
      在basicForm的fields中寻找,利用id属性检查他们,然后用id属性呼叫applyTo方法

      reset() : BasicForm
      重置所有值

      setValues( Array/Object values ) : BasicForm
      设置值,参见getValues

      submit( Object options ) : BasicForm
      提交表单

      updateRecord( Record record ) : BasicForm
      利用当前更新record对象,参见loadRecord

      事件:
      actioncomplete : ( Form this, Action action )
      actionfailed : ( Form this, Action action )
      beforeaction : ( Form this, Action action )


      Ext.form.Field
      有了form之后,我们当然还需要field
      方法:
      Field( Object config )
      其中config设置为{
          autoCreate : String/Object,    //一个{tag: "input", type: "text", size: "20", autocomplete: "off"}这样的对象,或者选                    择true,就是前面所说的那个固定内置对象
          clearCls : String,        //,默认x-form-clear-left
          cls : String,            //默认样式
          disabled : Boolean,       
          fieldClass : String        //x-form-field
          fieldLabel : String       
          focusClass : String        //x-form-focus
          hideLabel : Boolean        //隐藏前导标签
          inputType : String        //input type="???"
          invalidClass : String        //x-form-invalid
          invalidText : String       
          itemCls :String
          labelSeparator : String        //分隔符
          msgFx : String
          msgTarget : String
          name : String
          readOnly : Boolean
          tabIndex : Number
          validateOnBlur : Boolean    //true
          validationDelay : Number    //250
          validationEvent : String/Boolean    //KeyUP
          value : Mixed
      }

      构造很麻烦的,但还好我们一般不会直接使用field

      clearInvalid() : void
      清除非法信息

      getName() : String
      getRawValue() : Mixed
      getValue() : Mixed
      isDirty() : void
      isValid( Boolean preventMark ) : Boolean
      markInvalid( String msg ) : void
      reset() : void
      setRawValue( Mixed value ) : void
      setValue( Mixed value ) : void
      validate() : Boolean

      都很简单也略过了
      事件
      blur : ( Ext.form.Field this )
      change : ( Ext.form.Field this, Mixed newValue, Mixed oldValue )
      focus : ( Ext.form.Field this )
      invalid : ( Ext.form.Field this, String msg )
      specialkey : ( Ext.form.Field this, Ext.EventObject e )
      valid : ( Ext.form.Field this )

      Ext.form.Checkbox
      继承自Field, 复选框

       Checkbox( Object config )
       构造,其中config{
          autoCreate : String/Object,
          boxLabel : String,
          checked : Boolean,
          fieldClass : String,//x-form-field
          focusClass : String,
       }

      getValue() : Boolean
      initComponent() : void
      setValue( Boolean/String checked ) : void

      事件
      check : ( Ext.form.Checkbox this, Boolean checked )

      Ext.form.Radio
      继承自Ext.form.Checkbox,单选框
      多了一个方法
      getGroupValue() : String
      如果单选框是一组radio 的一部分,取当前选中的值

      Ext.form.Hidden
      继承自Field,隐藏字段,无新特性


      Ext.form.HtmlEditor
      继承自Field,这个htmleditor功能太简单了,什么人能扩充一下就好了

      config定义{
      createLinkText : String    //
      defaultLinkValue : String    // http://
      enableAlignments : Boolean
      enableColors : Boolean
      enableFont : Boolean
      enableFontSize : Boolean
      enableFormat : Boolean
      enableLinks : Boolean
      enableLists : Boolean
      enableSourceEdit : Boolean
      fontFamilies : Array    //这个当然要用汉字的字体组成的数组了
      }

      方法

      cleanHtml( String html ) : void
      createToolbar( HtmlEditor editor ) : void
      execCmd( String cmd, [String/Boolean value] ) : void
      getDocMarkup() : void
      getToolbar() : Ext.Toolbar
      insertAtCursor( String text ) : void
      pushValue() : void
      relayCmd( String cmd, [String/Boolean value] ) : void
      syncValue() : void
      toggleSourceEdit( [Boolean sourceEdit] ) : void
      updateToolbar() : void


      要提一点的是,要使用HtmlEditor,别忘了先Ext.QuickTips.init();



      Ext.form.TextField
      config{
          allowBlank : Boolean    //允许为空
          blankText : String    //如果为空验证错误时的提示文字 ,默认This field is required
          disableKeyFilter : Boolean
          emptyClass : String
          emptyText : String
          grow : Boolean    // 自动生长?,如果需要,会加宽当前input type="text"
          growMax : Number
          growMin : Number
          maskRe : RegExp    //仅允许输入与maskRe匹配的按键
          maxLength : Number
          maxLengthText : String    //超出最大长度时提示文本
          minLength : Number
          minLengthText : String    //不够最小长度时提示信息
          regex : RegExp        //正则匹配
          regexText : String    //提示
          selectOnFocus : Boolean
          validator : Function    //自定义验证方法,接受当前字段的值,如果合法,返回真,反之返回自定义信息
          vtype : String    //Ext.form.VTypes 中定义的vtype类型名,支持简单的类型验证
          vtypeText : String//如果不是,则提示
      }

      方法:
      TextField( Object config )
      构造

      autoSize() : void
      自动尺寸

      reset() : void
      重置

      selectText( [Number start], [Number end] ) : void
      选择文本

      validateValue( Mixed value ) : Boolean
      验证值
      posted @ 2008-05-23 21:18 meetrice 阅读(429) 评论(0) 编辑
      posted @ 2008-05-23 21:18 meetrice 阅读(376) 评论(0) 编辑
      Ext.data.Tree
      继承自Observable,用于存放树装的数据结构

      方法
      Tree( [Node root] )
      以root为根构造Ext.data.Tree对象

      getNodeById( String id ) : Node
      由指定id得到节点

      getRootNode() : Node
      得到根节点,由属性root得到更方便

      setRootNode( Node node ) : Node
      设置根节点

      事件有
      append : ( Tree tree, Node parent, Node node, Number index )
      beforeappend : ( Tree tree, Node parent, Node node )
      beforeinsert : ( Tree tree, Node parent, Node node, Node refNode )
      beforemove : ( Tree tree, Node node, Node oldParent, Node newParent, Number index )
      beforeremove : ( Tree tree, Node parent, Node node )
      insert : ( Tree tree, Node parent, Node node, Node refNode )
      move : ( Tree tree, Node node, Node oldParent, Node newParent, Number index )
      remove : ( Tree tree, Node parent, Node node )


      Ext.data.Node
      节点
      属性
      attributes : Object
      节点属性集

      childNodes : Array
      子节点

      firstChild : Node
      第一个子节点

      id : String
      id

      lastChild : Node
      最后一个子节点

      nextSibling : Node
      下一个兄弟节点

      parentNode : Node
      父节点

      previousSibling : Node
      前一个兄弟节点

      Node( Object attributes )
      构造节点

      appendChild( Node/Array node ) : Node
      将node做为附加在当前节点的lastChild之后


      bubble( Function fn, [Object scope], [Array args] ) : void
      由当前节点开始一直上溯到根节点,对于每个节点应用fn,直到有一个fn返回假为止


      cascade( Function fn, [Object scope], [Array args] ) : void
      由当前节点开始一下对每个子孙节点应用fn.直到返回false为止

      contains( Node node ) : Boolean
      当前节点是node的祖先节点?

      eachChild( Function fn, [Object scope], [Array args] ) : void
      基本同cascade,但只针对子节点应用fn

      findChild( String attribute, Mixed value ) : Node
      在子节点中找到第一个有属性attribute值为value的节点

      findChildBy( Function fn, [Object scope] ) : Node
      在子节点中找到第一个应用fn返回真的节点

      getDepth() : Number
      得到当前节点深度,根节点深度为0

      getOwnerTree() : Tree
      得到当前节点的Tree对象

      getPath( [String attr] ) : String
      得到当前节点的路径,默认attr为id

      indexOf( Node node ) : Number
      node在当前节点的子节点中的位置

      insertBefore( Node node, Node refNode ) : Node
      在参考节点refNode之前插入node节点

      isAncestor( Node node ) : Boolean
      当前节点是node的祖先节点?

      isFirst() : Boolean
      isLast() : Boolean
      当前节点是父节点的第一/最后一个节点

      isLeaf() : Boolean
      是叶节点?指不含子节点

      item( Number index ) : Node
      第index个子节点

      removeChild( Node node ) : Node
      移除node子节点

      replaceChild( Node newChild, Node oldChild ) : Node
      用newchild替换oldchild子节点

      sort( Function fn, [Object scope] ) : void
      用指定的fn排序子节点

      事件略
      posted @ 2008-05-23 21:18 meetrice 阅读(415) 评论(0) 编辑
      posted @ 2008-05-23 21:17 meetrice 阅读(516) 评论(0) 编辑
      Ext.data.Store
      store是一个为Ext器件提供record对象的存储容器,行为和属性都很象数据表

      方法:不列举继承来的方法
      Store( Object config )
      构造,config定义为{
       autoLoad : Boolean/Object,    //自动载入
       baseParams : Object,    //只有使用httpproxy时才有意义
       data : Array,        //数据
       proxy : Ext.data.DataProxy,//数据代理
       pruneModifiedRecords : boolean,//清除修改信息
       reader : Ext.data.Reader,    //数据读取器
       remoteSort : boolean,    //远程排序?
       sortInfo : Object,    //{field: "fieldName", direction: "ASC|DESC"}这样的排序对象
       url : String,        //利用url构造HttpProxy
      }

      add( Ext.data.Record[] records ) : void
      增加记录records 到store

      addSorted( Ext.data.Record record ) : void
      增加record到store并排序(仅本地排序时有用)

      clearFilter( Boolean suppressEvent ) : void
      清除过滤器

      collect( String dataIndex, [Boolean allowNull], [Boolean bypassFilter] ) : Array
      收集由dataIndex指定字段的惟一值

      commitChanges() : void
      提交Store所有的变更,会引发Update事件


      filter( String field, String/RegExp value, [Boolean anyMatch], [Boolean caseSensitive] ) : void
      设定过滤器
      field:String    //字段名
      value:String    //RegExp 如果是字符器,检查field是否以value开始,如果是正则,检查是否匹配
      anyMatch:Boolean //匹配任何部分而不仅令是开始
      caseSensitive:Boolean //大小写敏感?

      filterBy( Function fn, [Object scope] ) : void
      更强悍的过滤方法.fn接收两个参数record和id

      find( String property, String/RegExp value, [Number startIndex], [Boolean anyMatch], [Boolean caseSensitive] ) : Number
      找到符合条件的第一条记录,参数同filter

      findBy( Function fn, [Object scope], [Number startIndex] ) : Number
      参见filterBy

      getAt( Number index ) : Ext.data.Record
      getById( String id ) : Ext.data.Record
      依充号/id得到record对象

      getCount() : void
      得到记录数

      getModifiedRecords() : Ext.data.Record[]
      得到修改过的记录集

      getRange( [Number startIndex], [Number endIndex] ) : Ext.data.Record[]
      得到指定范围的记录集合

      getSortState() : void
      得到排序状态:显然不是void而是返回一个排序对象,同sortInfo一样的结构{field: "fieldName", direction: "ASC|DESC"}

      getTotalCount() : void
      这个对于翻页信息还是很有用的

      indexOf( Ext.data.Record record ) : Number
      indexOfId( String id ) : Number
      由记录或id得到序号

      insert( Number index, Ext.data.Record[] records ) : void
      在指定的位置插入记录,并引发add事件

      isFiltered() : Boolean
      当前设置了过滤器则返回真

      load( Object options ) : void
      由指定的Proxy使用指定的reader读取远程数据
      options定义为
      {
          params :Object,    //请求url需要附加的参数
          callback :Function//回叫方法,接收三个参数
            //r : Ext.data.Record[] //返回的record数组
            //options: Options load方法传入的options
            //success: Boolean //成功
          scope :Object, //范围.默认是store本身
          add :Boolean 追加还是更新
      }


      loadData( Object data, [Boolean append] ) : void
      用法比load简单一点,目的是一样的,只是这次数据由本地读取

      query( String field, String/RegExp value, [Boolean anyMatch], [Boolean caseSensitive] ) : MixedCollection
      queryBy( Function fn, [Object scope] ) : MixedCollection
      查询,参数和find类似,但返回所有符合条件的record,而不是第一个符合条件记录的序号

      rejectChanges() : void
      放弃所有的变更

      reload( [Object options] ) : void
      重新载入,相当于 load(options,false),如果连options都没有传入,则取最后一次load时使用的参数

      remove( Ext.data.Record record ) : void
      移除指定记录

      removeAll() : void
      移除所有记录

      setDefaultSort( String fieldName, [String dir] ) : void
      设置默认排序规则

      sort( String fieldName, [String dir] ) : void
      排序

      sum( String property, Number start, Number end ) : Number
      对property字段由start开始到end求和

      事件列表
      add : ( Store this, Ext.data.Record[] records, Number index )
      beforeload : ( Store this, Object options )
      clear : ( Store this )
      datachanged : ( Store this )
      load : ( Store this, Ext.data.Record[] records, Object options )
      loadexception : ()
      metachange : ( Store this, Object meta )
      remove : ( Store this, Ext.data.Record record, Number index )
      update : ( Store this, Ext.data.Record record, String operation )
      看名字都很简单,参数也不复杂,略过


      用例
      //得到远程json对象
      //
      其中jsoncallback.js内容为
      //
      { 'results': 2, 'rows': [
      //
          { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
      //
          { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
      //
      }
      //
      定义proxy
            var proxy=new Ext.data.HttpProxy({url:'jsoncallback.js'});
      //定义reader
            var reader=new Ext.data.JsonReader(
              
      {
              totalProperty: 
      "results",//totalRecords属性由json.results得到
              root: "rows",            //构造元数据的数组由json.rows得到
              id: "id"                //id由json.id得到
              }
      ,[
              
      {name: 'name', mapping: 'name'},
              
      {name: 'occupation'}            //如果name与mapping同名,可以省略mapping
              ]
          )
      //构建Store   
          var store=new Ext.data.Store({
            proxy:proxy,
            reader:reader
         }
      );
      //载入
      store.load();


      示例2
      //得到远程xml文件
      //其中xml文件内容为
      <?xml version="1.0" encoding="utf-8" ?>
      <dataset>
        
      <results>2</results>
        
      <row>
          
      <id>1</id>
          
      <name>Bill</name>
          
      <occupation>Gardener</occupation>
        
      </row>
        
      <row>
          
      <id>2</id>
          
      <name>Ben</name>
          
      <occupation>Horticulturalist</occupation>
        
      </row>
      </dataset>


      var proxy=new Ext.data.HttpProxy({url:'datasource.xml'});
         
          
      var reader = new Ext.data.XmlReader({
             totalRecords: 
      "results",
             record: 
      "row",        
             id: 
      "id"                
          }
      , [
             
      {name: 'name', mapping: 'name'},
             
      {name: 'occupation'}           
          ]);
         
      var store=new Ext.data.Store({
            proxy:proxy,
            reader:reader
         }
      );
      store.load();


      示例3
      //从本地数组得到
       var arr=[ [1'Bill''Gardener'], [2'Ben''Horticulturalist'] ];
      var reader = new Ext.data.ArrayReader(
         
      {id: 0},
         [
          
      {name: 'name', mapping: 1},        
          
      {name: 'occupation', mapping: 2}   
          ]);
         
          
      var store=new Ext.data.Store({
            reader:reader
         }
      );
         store.loadData(arr); 
      posted @ 2008-05-23 21:17 meetrice 阅读(307) 评论(0) 编辑
      Ext.data.DataReader
      纯虚类,从数据源得到结构化数据转换为元数据对象,对象包含Record的集合,一般用做Store对象的元数据,
      具有如下格式
      {
      totalRecord:int,
      records:Array of Ext.data.Record
      }
      具体使用参见三个子类
      Ext.data.ArrayReader/Ext.data.JsonReader/Ext.data.XmlReader


      方法
      DataReader( Object meta, Object recordType )
      构造

      Ext.data.ArrayReader
      用于读数组到一个元数据对象

      ArrayReader( Object meta, Object recordType )
      构造,第一个参数是配置除了可以指示使用哪个字段做id外,不懂其它的用法,
      第二个参数是recordType与record对象的create方法的参数一样,是一样config对象数组,具体参见
      readRecords( Object o ) : Object
      读取o,返回一个元数据对象

      用例示范:
      //定义数组
      var arr=[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ];
      var reader = new Ext.data.ArrayReader(
      //以第一个元素做为recordid
         {id: 0},
      //定义数组到record的映射关系
         [
          {name: 'name', mapping: 1},        
          {name: 'occupation', mapping: 2}   
         ]
      );
      //生成元数据
      var data=reader.readRecords(arr);

      Ext.data.JsonReader
      用于将一个json对象转换为元数据对象

      JsonReader( Object meta, Object recordType )
      JsonReader的构造参数meta可以有更多选择,
      {
        id : String,
        root : String,
        successProperty : String,
        totalProperty : String
      }
      都是对应json对象的属性名

      read( Object response ) : Object
      从一个response对象返回,response.responseText属性应仅含有一个json格式数据块

      readRecords( Object o ) : Object
      读取o,返回一个元数据对象

      使用示例:
           var json={ 'results': 2, 'rows': [
          { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
          { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
      };
          var reader=new Ext.data.JsonReader(
              {
              totalProperty: "results",//totalRecords属性由json.results得到
              root: "rows",            //构造元数据的数组由json.rows得到
              id: "id"                //id由json.id得到
              },[
              {name: 'name', mapping: 'name'},
              {name: 'occupation'}            //如果name与mapping同名,可以省略mapping
              ]
          )
          var data=reader.readRecords(json);



      Ext.data.XmlReader
      xmlreader对象当然是为xml而准备的

      构造:
      XmlReader( Object meta, Mixed recordType )
      meta与jsonreader类似,
      meta是一个{
          id : String,
          record : String,
          success : String,
          totalRecords : String
      }对象,只是这些字符串都是相对于文档根目录的domquery路径
      read( Object response ) : Object
      readRecords( Object doc ) : Object
      ....


      var str=["<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
          "<dataset>",
       "<results>2</results>",
       "<row>",
         "<id>1</id>",
         "<name>Bill</name>",
         "<occupation>Gardener</occupation>",
       "</row>",
       "<row>",
         "<id>2</id>",
         "<name>Ben</name>",
         "<occupation>Horticulturalist</occupation>",
       "</row>",
      "</dataset>"].join("");

      //生成xmldocument对象
      var xmlDocument;
       if(Ext.isIE){
          xmlDocument = new ActiveXObject("Msxml2.FreeThreadedDOMDocument")
          xmlDocument.async=false;
          xmlDocument.resolveExternals = false;
          xmlDocument.loadXML(str)
      }
      else{
         xmlDocument = (new DOMParser()).parseFromString(str, "text/xml");
      }

      //然后开始...和其它两个reader一样的用法,只是这儿换了一种写法,recordtype也可以是一个record对象
      var record = Ext.data.Record.create([
         {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
         {name: 'occupation'}                 // This field will use "occupation" as the mapping.
      ])
      var reader = new Ext.data.XmlReader({
         totalRecords: "results",
         record: "row",           //row是节点选择器
         id: "id"                
      }, record);
      var data=reader.readRecords(xmlDocument);
      posted @ 2008-05-23 21:16 meetrice 阅读(281) 评论(0) 编辑
      Ext.data.DataProxy
      数据代理类是一个纯虚类,主要用于生成Ext.data.Record对象,没有公开的属性和方法,只是归定子类需要处理三个事件
      beforeload : ( Object This, Object params )
      load : ( Object This, Object o, Object arg )
      loadexception : ( Object This, Object o, Object arg, Object e )
      事实上参数也是子类自定义的

      Ext.data.HttpProxy
      api文档中说httpProxy是从object继承来的,事实上source中它和下面的Ext.data.MemoryProxy/Ext.data.ScriptTagProxy都继承于DataProxy
      HttpProxy用于远程代理,而且服务端返回信息时必须指定Content-Type属性为"text/xml".

      HttpProxy( Object conn )
      构造一个HttpProxy对象,参数可以是一个类似于{url: 'foo.php'}这样的json对象,也可以是一个Ext.data.Connection对象,如果参数没有指定,将使用Ext.Ajax对象将被用于发起请求

      getConnection() : Connection
      得到当前连接对象

      load( Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg ) : void
      从配置的connection对象得到record数据块,并激发callback
      params:        发起http请求时所要传递到服务端的参数
      DataReader:    见DataReader
      callback:    回叫方法,第一个参数为接收到的信息,第二个参数为arg,第三个是成功标志
      scope:        范围
      arg:        这儿的参数将会传递给回叫函数callback

      使用示例:
      var proxy=new Ext.data.HttpProxy({url:'datasource.xml'});
          //关于reader将会在Ext.data.DataReader中讲解
          var reader = new Ext.data.XmlReader({
             totalRecords: "results",
             record: "row",        
             id: "id"                
          }, [
             {name: 'name', mapping: 'name'},
             {name: 'occupation'}           
          ]);
         
          //定义回叫方法
          var metadata;
          function callback(data,arg,success){
              if(success){
                  metadata=data;
              }
          }
          //从connection配置的url中利用reader将返回的xml文件转为元数据,并传递给callback
          proxy.load( null,reader,callback,this);

      Ext.data.MemoryProxy
      MemoryProxy( Object data )
      构造
      load( Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg ) : void
      取数据,和HttpProxy类似,只是params参数没有被使用

      使用示例
      var proxy=new Ext.data.MemoryProxy([ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]);
      var reader = new Ext.data.ArrayReader(
      {id: 0},
      [
      {name: 'name', mapping: 1},        
      {name: 'occupation', mapping: 2}   
      ]);

      var metadata;
      function callback(data,arg,success){
          metadata=data;
      }
      proxy.load( null,reader,callback,this);


      Ext.data.ScriptTagProxy
      这个类和HttpProxy类似,也是用于请求远程数据,但能用于跨主域调用,如果请求时使用了callback参数
      则服务端应指定Content-Type属性为"text/javascript"
      并返回callback(jsonobject)
      反之则应置Content-Type属性为"application/x-json"
      并直接返回json对象

      ScriptTagProxy( Object config )
      构造,其中
      config定义为{
      callbackParam : String,    //回叫参数
      nocache : Boolean,    //是否缓存
      timeout : Number,    //超时
      url : String        //请求数据的url
      }

      abort() : void
      放弃

      load( Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg ) : void
      参见HttpProxy

       

      posted @ 2008-05-23 21:16 meetrice 阅读(414) 评论(0) 编辑
      Ext.data.Connection
      访问指定的url,这是个异步调用类,如果想得到服务器信息,请在request参数中指定callback方法或指定侦听者(对文件上传无效)

      Connection( Object config )
      构造,config定义为{
       autoAbort : Boolean,
       defaultHeaders : Object,
       disableCaching : Boolean,
       extraParams : Object,
       method : String,
       timeout : Number,
       url : String
      }
      对象

      方法:由    Observable继承过来的方法省略
      abort( [Number transactionId] ) : void
      放弃请求,如果同时有多个请求发生,参数指示请求进程序号,不指定则是放弃最后一个请求

      isLoading( [Number transactionId] ) : Boolean
      第transactionId个请求是否完成载入,未批定指最后一个

      request( [Object options] ) : Number
      最实用的当然是这个方法了,返回的正是前面的两个方法所需要的进程id
      其中options定义为{
      url:string,    //请求url
      params:Object/String/Function, //以post方法请求时传递的参数
      method:string ,        //Get/Post
      callback:Function,    //回叫方法,不管是成功还是失败都会呼叫这个方法,有三个参数,由options传入的options参数,success:Boolean,成功?response:Object, 含有返回数据的XMLHttpRequest对象
      success:Function,    //成功时回叫,第一个参数为XMLHttpRequest对象,第二个参数传入指定的options
      failure:Function,    //失败时回叫,参数同success
      scope:Object,        //范围
      form:Object/String,    //一个form对象或它的id,可以由此自动生成参数params
      isUpload:Boolean,    //文件上传?通常可以自动检测
      headers:Object,        //要自定义的请求头信息
      xmlData:Object        //一个xml文档对象,它将通过url附加参数的方式发起请求
      disableCaching:Boolean    //是否禁用缓存?默认为真
      }

      Ext.Ajax
      由Ext.data.Connection 继承而来,方法和父类一模一样,但使用起来更简单一些,是一个全局惟一静态类
      示例:
      Ext.Ajax.request({
         url: 'foo.php',
         success: someFn,
         failure: otherFn,
         headers: {
             'my-header': 'foo'
         },
         params: { foo: 'bar' }
      });


      Ext.Ajax.request({
          form: 'some-form',
          params: 'foo=bar'
      });

      //所有的Ext.Ajax请求都会加个这个默认的头
      Ext.Ajax.defaultHeaders = {
          'Powered-By': 'Ext'
      };

      //所有的Ext,Ajax在发起请求前都会调用showSpinner
      Ext.Ajax.on('beforerequest', this.showSpinner, this);


      Ext.data.Record
      基本上可以理解为.net中的datarow或者sql server中的一行数据,它存放了数据的定义信息和他们的值
      [公有属性]
      data : Object        数据内容,一个json对象
      dirty : Boolean        是否修改过
      id : Object        惟一ID,默认从1000开始以1剃增
      modified : Object    如果记录没有修改过,为null如果修改过则存放原始值信息
      [公有方法]
      Record( Array data, [Object id] )
      这个构造方法并不用于创建记录对象,相反,应该使用create方法来创建record对象,参数data定义见create方法,id默认递增起始id

      beginEdit() : void
      开始修改

      cancelEdit() : void
      放弃所做的修改,参见commit

      copy( [String id] ) : Record
      //创建当前record的一个克隆值,如果未指定id使用当前id+1

      commit( [Boolean silent] ) : void
      commit方法一般会被Store对象调用而不是recorde本身,提交自创建或最后一次修改后的所有变更,如果silent为真将不会通知store对象


      create( [Array o] ) : function
      静态构造方法 o是config数组
      其中config可以含有如下属性
      {
      name : String     //字段名
      mapping : String //用于reader时的映射关系,如果是用于jsonreader,使用相对当前记录的javascript表达式
              //,如果是用于xmlreader,则是相对于记录的domquery表达式,对于ArrayReader,则是序号
      type:String    //可选值 auto /string/int/float/boolean/date,其中auto是默认值,不进行转换
      sortType : Mixed //排序类型,Ext.data.SortTypes成员之一,参见sortTypes
      sortDir : String  //正序倒序 ASC/DESC值之一
      convert : Function    //转换函数,这个功能很有用,可自定义,接收当前value返回处理后的value
      dateFormat : String    //日期格式化字符串,convert:function的一个特例,使用Date.parseDate方法转换当前日期
      }


      endEdit() : void
      结束修改

      get( name {String} ) : Object
      指定命名字段string的值

      getChanges() : Object
      返回修改记录的对象

      reject( [Boolean silent] ) : void
      和commit相似,当然是拒绝所做的修改

      set( String name, Object value ) : void
      为字段name设定新值value
      posted @ 2008-05-23 21:15 meetrice 阅读(291) 评论(0) 编辑
      Ext.KeyNav
      Ext的keyNav类能为Ext.Element元素提供简单的按键处理方法
      例:
      var el=Ext.get("textarea");
      new Ext.KeyNav(el, {
          "left" : function(e){
              alert("left key down");
              },
          scope : el
          }
      );
      它的行为与KeyMap类似,但功能比KeyMap要弱小的多,只能处理以下已定义键
      enter/left/right/up/down/tab/esc/pageUp/pageDown/del/home/end
      同情一下KeyNav

      方法只有三个,不用多解释
      KeyNav( Mixed el, Object config )
      disable() : void
      enable() : void

      Ext.KeyMap类
      则强悍的多,其中最重要的当然是对按键的定义更灵活
      例:上例用KeyMap来写可能是
      var el=Ext.get("textarea");
      new Ext.KeyMap(el, {
              key:Ext.EventObject.LEFT,
              fn: function(e){
                  alert("left key down");
              },
              scope : el
          }
      );

      方法
      KeyMap( Mixed el, Object config, [String eventName] )
      构造,与KeyNav也相似,但更灵活
      它是{
      key:        String/Array,     //可以是数字,字符,也可以是Ext.EventObject.LEFT这样的助记符,还能是他们组成的数组
      shift:       Boolean,          //ctrl键按下?
      ctrl:        Boolean,
      alt :        Boolean,
      fn  :        Function,         //回叫方法
      scope:       Object          //范围
      }这样的对象或它们组成的数组
      比如{key: 10},{key: [10,13]},{key:'\t'},{key:'abcd'},{key:Ext.EventObject.LEFT}都是合法的定义

      addBinding( Object/Array config ) : void
      增加新的绑定动作 config参见构造

      disable() : void
      enable() : void
      isEnabled() : Boolean
      允许,静止和状态查询

      on( Number/Array/Object key, Function fn, [Object scope] ) : void
      只添加一个处理时addBinding的快捷方式,但个人感觉并没有简单到哪儿去。


      Ext.util.JSON
      轮到大名鼎鼎的JSON了,可惜Ext提供的JSON对象功能好弱小,只有encode主decode两个方法
      而且只能编码String/Array/Date,至少也要搞个 xml2json/json2xml方法呀

      Ext.util.Format
      主要提供了一些格式化方法

      capitalize( String value ) : String
      首字母大写

      date( Mixed value, [String format] ) : String
      格式化日期输出,还是Date.format方法好用

      dateRenderer( String format ) : Function
      返回一个利用指定format格式化日期的方法

      defaultValue( Mixed value, String defaultValue ) : String
      如果value未定义或为空字符串则返回defaultValue

      ellipsis( String value, Number length ) : String
      如果value的长度超过length的,取前length-3个并用...替代,对中国人来说还是垃圾功能,用的字符串长度不是字节长度

      fileSize( Number/String size ) : String
      简单的格式化文件长度为 xxxbytes xxxKB xxxMB,没有GB哟

      htmlEncode( String value ) : String
      htmlDecode( String value ) : String
      HTML编码解码,将& <  >  “替换为&amp;&lt;&gt;&quot;

      lowercase( String value ) : String
      将value转换为全小写

      stripScripts( Mixed value ) : String
      去除脚本标签

      stripTags( Mixed value ) : String
      去除HTML标签

      substr( String value, Number start, Number length ) : String
      取子字符串

      trim( String value ) : String
      去除开头和结尾的空格

      undef( Mixed value ) : Mixed
      如果value未定义,返回空字符串,反之返回value本身

      uppercase( String value ) : String
      转为全大写

      usMoney( Number/String value ) : String
      转为美元表示

      Ext.util.DelayedTask
      提供一个setTimeout的简单替代方法

      公开的方法也只有三个
      DelayedTask( [Function fn], [Object scope], [Array args] )
      delay( Number delay, [Function newFn], [Object newScope], [Array newArgs] ) :
      cancel() : void
      简单的示例用法如果
      var task=new Ext.util.DelayedTask(Ext.emptuFn);
      task.delay(1000);
      task.cancel();

      Ext.util.TaskRunner
      增强版的DelayedTask,能提供多线程的定时服务,
      例:
      var task = {
          run: function(){
              Ext.fly('clock').update(new Date().format('g:i:s A'));
          },
          interval: 1000
      }
      var runner = new Ext.util.TaskRunner();
      runner.start(task);

      四个方法都很简单
      TaskRunner( [Number interval] )
      start( [Object task] ) : Object
      stop( Object task ) : Object
      stopAll() : void


      Ext.util.TextMetrics
      这个类主要是为了准备的得到块状化文本正确的高度和宽度
      例:
      var metrics=Ext.util.TextMetrics.createInstance('div');
      metrics.setFixedWidth(100);
      var size=metrics.getSize("中华人民共和国中华人民共和国中华人民共和国中华人民共和国");
      Ext.MessageBox.alert("getsize",String.format("width:{0}px\theight:{1}px",size.width,size.height))

      方法
      bind( String/HTMLElement el ) : void
      绑定到el

      createInstance( String/HTMLElement el, [Number fixedWidth] ) : Ext.util.TextMetrics.Instance
      为el创建TextMetrics实例

      getHeight( String text ) : Number
      getSize( String text ) : Object
      getWidth( String text ) : Number
      得到尺寸

      measure( String/HTMLElement el, String text, [Number fixedWidth] ) : Object
      测算文本text在el中将要占用的尺寸

      setFixedWidth( Number width ) : void
      设置指定的宽度

      Ext.XTemplate
      增强型模板,支持更多功能了,虽然方法不多,但用起来来还真的很麻烦,但并不建议大家学习这样的自定义语法,不如用xslt
      另外这个Xtemplate虽然命名空间在Ext之下,但源文件却是放在util目录中的
      XTemplate( String/Array html )
      XTemplate.from( String/HTMLElement el ) : Ext.XTemplate
      apply() : void
      applyTemplate( Object values ) : String
      compile() : Function
      这些方法Ext.Template中都有说明,
      posted @ 2008-05-23 21:15 meetrice 阅读(202) 评论(0) 编辑
      Ext.Fx类
      对于我这样的懒鬼而言,Fx类是核心类库中最激动人心的一个类,它不是最重要的,却是最实用的一个类
      定义了一些常用的特效方法,不妨自己多动手试试下面的方法,很有趣的

      fadeIn( [Object options] ) : Ext.Element
      渐显 options参数有以下属性
      callback:Function    完成后的回叫方法
      scope:Object        目标
      easing:String        行为方法 默认值是:easeOut,可选值在ext_base中找到,但没有说明,以下内容从yahoo ui中找到的
      easeNone:匀速
      easeIn:开始慢且加速
      easeOut:开始快且减速
      easeBoth:开始慢且减速
      easeInStrong:开始慢且加速,t的四次方
      easeOutStrong:开始快且减速,t的四次方
      easeBothStrong:开始慢且减速,t的四次方
      elasticIn:
      elasticOut:
      elasticBoth:
      backIn:
      backOut:
      backBoth:
      bounceIn:
      bounceOut:
      bounceBoth:
      太多,慢慢体会吧
      afterCls:String        事件完成后元素的样式
      duration:Number        事件完成时间(以秒为单位)
      remove:Boolean        事件完成后元素销毁?
      useDisplay:Boolean    隐藏元素是否使用display或visibility属性?
      afterStyle:String/Object/Function        事件完成后应用样式
      block:Boolean        块状化?
      concurrent:Boolean    顺序还是同时执行?
      stopFx :Boolean    当前效果完成后随合的效果是否将停止和移除

      fadeOut( [Object options] ) : Ext.Element
      渐隐 fadeOut和fadeIn能使用一个特别的endOpacity属性以指示结束时的透明度
      例:el.fadeIn({duration:5,endOpacity:0.7});

      frame( [String color], [Number count], [Object options] ) : Ext.Element
      边框变亮扩展然后渐隐
      例:el.frame("ff0000", 10, { duration: 3 })

      ghost( [String anchor], [Object options] ) : Ext.Element
      渐渐滑出视图,anchor定义
      tl     左上角(默认)
      t      上居中
      tr     右上角
      l      左边界的中央
      c      居中
      r      右边界的中央
      bl     左下角
      b      下居中
      br     右下角
      例:
      el.ghost('b', {
          easing: 'easeOut',
          duration: .5
          remove: false,
          useDisplay: false
      });

      hasActiveFx() : Boolean
      指示元素是否当前有特效正在活动

      hasFxBlock() : Boolean
      是否有特效阻塞了

      highlight( [String color], [Object options] ) : Ext.Element
      高亮显示当前元素
      例:el.highlight("ffff9c", {
          attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
          endColor: (current color) or "ffffff",
          easing: 'easeIn',
          duration: 1
      });


      pause( Number seconds ) : Ext.Element
      暂停

      puff( [Object options] ) : Ext.Element
      吹,吹,吹个大气球,元素渐大并隐没
      例:el.puff({
          easing: 'easeOut',
          duration: .5,
          remove: false,
          useDisplay: false
      });

      scale( Number width, Number height, [Object options] ) : Ext.Element
      缩放
      例:el.scale(
          [element's width],
          [element's height], {
          easing: 'easeOut',
          duration: .35
      });

      sequenceFx()
      排队特效

      shift( Object options ) : Ext.Element
      位移,并可重置大小,透明度等
      例:
      el.shift({
          width: [element's width],
          height: [element's height],
          x: [element's x position],
          y: [element's y position],
          opacity: [element's opacity],
          easing: 'easeOut',
          duration: .35
      });

      slideIn( [String anchor], [Object options] ) : Ext.Element
      slideOut( [String anchor], [Object options] ) : Ext.Element
      滑入/滑出
      例:el.slideIn('t', {
          easing: 'easeOut',
          duration: .5
      });


      stopFx() : Ext.Element
      停止特效

      switchOff( [Object options] ) : Ext.Element
      收起并隐没
      例:
      el.switchOff({
          easing: 'easeIn',
          duration: .3,
          remove: false,
          useDisplay: false
      });


      syncFx() : Ext.Element
      异步特效
      posted @ 2008-05-23 21:15 meetrice 阅读(122) 评论(0) 编辑
      Ext.EventManager
      事件管理者中的大部分方法都在Ext中有定义,主要用于事件管理


      addListener( String/HTMLElement el, String eventName, Function handler,
      on( String/HTMLElement el, String eventName, Function handler, [Object scope], [Object options] ) : void
      onDocumentReady( Function fn, [Object scope], [boolean options] ) : void
      removeListener( String/HTMLElement el, String eventName, Function fn ) :
      un( String/HTMLElement el, String eventName, Function fn ) : Boolean
      参见Ext

      onWindowResize( Function fn, Object scope, boolean options ) : void
      窗口大小变更时触发

      onTextResize( Function fn, Object scope, boolean options ) : void
      活动文本尺寸变更时触发



      Ext.EventObject
      这两个类都定义在EventManager.js中,分开是为了逻辑上更清晰吧,这个类主要用于描述事件本身,一般用做事件处理方法的参数
      另外这个害定义了一些键值常量,比ascii码好记

      function handleClick(e){ // 这儿的e就是一个EventObject对象
          e.preventDefault();
          var target = e.getTarget();
          ...
       }
       var myDiv = Ext.get("myDiv");
       myDiv.on("click", handleClick);
       //or
       Ext.EventManager.on("myDiv", 'click', handleClick);
       Ext.EventManager.addListener("myDiv", 'click', handleClick);

      getCharCode() : Number
      getKey() : Number
      在非webkit|khtml类型网页中这两个方法是一样的,得到按键的值

      getPageX() : Number
      getPageY() : Number
      getXY() : Array
      得到事件坐标

      getRelatedTarget() : HTMLElement
      得到关联目标?我总是得到null

      getTarget( [String selector], [Number/Mixed maxDepth], [Boolean returnEl] ) :
      如果没有定义selector则直接返回target属性,如果定义了selector,则利用selector寻找祖先节点

      getTime() : Number
      得到事件发生的时间?

      getWheelDelta() : Number
      应该是个过时的方法,反正在ie和火狐下都不知道做什么用的,原意应该是得到鼠标的按键信息?

      hasModifier() : Boolean
      事件发生时是否同时按下了ctrl/alt/shift键之一?

      preventDefault() : void
      阻止浏览器的默认事件?

      stopEvent() : void
      preventDefault+stopPropagation

      stopPropagation() : void
      阻止事件冒泡

      within( Mixed el, [Boolean related] ) : Boolean
      如果事件的目标是el或者它的子节点将返回真


      Ext.CompositeElement类
      基础的复合元素类,为容器中每个元素创建一个Ext.Element对象
      虽然不是继承自Ext.Element,但事实上它几乎支持Element类的所有方法
      例:
      var els = Ext.select("#some-el div.some-class", true);
      els.setWidth(100);


      add( String/Array els ) : CompositeElement
      添加 css选择器els匹配的元素 或 元素组成的数组 到当前对象

      clear() : void
      清除所有元素

      contains() : Boolean
      应该是contains(Mixed el):Boolean,当前复合元素中是否含有el

      each( Function fn, [Object scope] ) : CompositeElement
      通过el,this,index参数为每个元素调用fn

      fill( String/Array els ) : CompositeElement
      clear()& add(els)

      filter( String selector ) : CompositeElement
      过滤

      first() : Ext.Element
      第一个元素

      getCount() : Number
      //元素的数量

      indexOf() : Boolean
      同contains一样应该有个Mixed参数

      item( Number index ) : Ext.Element
      第index个元素

      last() : Ext.Element
      最后一个元素

      removeElement( Mixed el, [Boolean removeDom] ) : CompositeElement
      删除el元素

      replaceElement( Mixed el, Mixed replacement, [Boolean domReplace] ) : CompositeElement
      替换

      Ext.CompositeElementLite
      由Ext.CompositeElement继承而来,重写了一些方法,但没看出与父类有什么不同
      addElements /invoke /item /addListener /each /indexOf /replaceElement
      posted @ 2008-05-23 21:14 meetrice 阅读(203) 评论(0) 编辑
      Ext.DomQuery类
      selector语法详见Ext类

      compile( String selector, [String type] ) : Function
      编写一个选择器或xpath查询到一个方法以方便重用,type取select(默认)或simple值之一

      filter( Array el, String selector, Boolean nonMatches ) : Array
      过滤el中的元素,保留符合selector的,如果nonMatches为真,结果相反

      is( String/HTMLElement/Array el, String selector ) : Boolean
      验证el是否匹配selector

      select( String selector, [Node root] ) : Array
      从root中选择匹配selector的对象数组

      selectNode( String selector, [Node root] ) : Element
      返回root中第一个匹配selector的对象

      selectNumber( String selector, [Node root], Number defaultValue ) : Number
      返回root中第一个匹配selector的对象的节点值,转换为整数或浮点数

      selectValue( String selector, [Node root], String defaultValue ) : void
      返回root中第一个匹配selector的对象的节点值,如果为null,用默认值defaultValue代替

      Ext.DomHelper类
      append( Mixed el, Object/String o, [Boolean returnElement] ) : HTMLElement/Ext.Element
      创建一个新的DOM元素并添加到el
      参数 o 是一个DOM对象或一个原始html块


      applyStyles( String/HTMLElement el, String/Object/Function styles ) : void
      应用样式styles到对象el, 样式的对象表示方法见Ext.Element

      createTemplate( Object o ) : Ext.Template
      由o创建一个新的Ext.Template对象,详见 Ext.Template

      insertAfter( Mixed el, Object o, [Boolean returnElement] ) : HTMLElement/Ext.Element
      insertBefore( Mixed el, Object/String o, [Boolean returnElement] ) : HTMLElement/Ext.Element
      创建一个新的DOM对象o并将他们挺入在el之后/之前

      insertFirst( Mixed el, Object/String o, [Boolean returnElement] ) :
      创建一个新的DOM元素并做为第一个子节点添加到el (看了这个insertFirst,建议将append取一个别名insertLast:))

      insertHtml( String where, HTMLElement el, String html ) : HTMLElement
      where 可选值beforeBegin/afterBegin/beforeEnd/afterEnd
      将html代码插入到el附近,

      markup( Object o ) : String
      返回DOM对象o对应的html代码

      overwrite( Mixed el, Object/String o, [Boolean returnElement] ) :
      创建一个新的DOM元素o并用它重写el的内容


      Ext.Template类
      Template类主要是功能是生产html片断,例
      var t = new Ext.Template(
          '<div name="{id}">',
              '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
          '</div>'
      );
      t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});

      公用方法:
      Template( String/Array html )
      构造一个Ext.Template对象,参数可以是字符串形式的html代码或它们组成的数组,

      Template.from( String/HTMLElement el, Object config ) : Ext.Template
      能过el的value(优先)或innerHTML来构造模板

      append( Mixed el, Object values, [Boolean returnElement] ) : HTMLElement/Ext.Element
      insertAfter( Mixed el, Object values, [Boolean returnElement] ) : HTMLElement/Ext.Element
      insertBefore( Mixed el, Object values, [Boolean returnElement] ) : HTMLElement/Ext.Element
      insertFirst( Mixed el, Object values, [Boolean returnElement] ) : HTMLElement/Ext.Element
      这组方法提供由 value产生的html 代码,并添加到dom 做为el的最后一个子节点/下一个兄弟节点/前一个兄弟节点/第一个子节点
      values解释参见applyTemplate

      apply() : void
      applyTemplate( Object values ) : String
      apply是applyTemplate的简写,如果参数是数字values可以是一个数组,或者一个象 {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'}这样的json对象


      compile() : Ext.Template
      编译模板,替换掉模板中的\=>\\ ,\r\n|\n==>\\n, '=\',主要是为了js自己处理方便

      overwrite( Mixed el, Object values, [Boolean returnElement] ) :
      利用values生成html替换el的内容

      set( String html, [Boolean compile] ) : Ext.Template
      设置模板的html,如果compile为真将调用compile方法

      posted @ 2008-05-23 21:14 meetrice 阅读(258) 评论(0) 编辑
      Ext.Element类

      Element( String/HTMLElement element, [Boolean forceNew] )
      由id或DOM节点创建Element对象

      Element.fly( String/HTMLElement el, [String named] ) : Element
      由id或DOM节点创建一个全局共享的活动元素,可由named命名以避免可能的冲突

      Element.get( Mixed el ) : Element
      由id或DOM节点或已存在的Element得到一个Ext.Element对象

      addClass( String/Array className ) : Ext.Element
      为元素添加一个或多个css类名

      addClassOnClick( String className ) : Ext.Element
      为点击事件添加和移除css类

      addClassOnFocus( String className ) : Ext.Element
      为得到和失去焦点添加和移除css类

      addClassOnOver( String className, [Boolean preventFlicker] ) : Ext.Element
      为鼠标移入移出事件添加和移除css类(该方法未实际使用preventFlicker参数)

      addKeyListener( Number/Array/Object/String key, Function fn, [Object scope] ) : Ext.KeyMap
      为对象添加按键侦听 key由数值或字符串或{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}这样的对象或他们的数组组成

      addKeyMap( Object config ) : Ext.KeyMap
      功能同addKeyListener,只是传参方式不同
      例:
      el.addKeyMap({key : "ab",ctrl : true,fn: fn,scope:el });

      el.addKeyListener({key:"ab",ctrl:true},fn,el);
      是等价的,都是在 按下ctral+a或ctrl+b后呼叫fn

      addListener( String eventName, Function fn, [Object scope], [Object options] ) : void
      定义事件侦听,eventName:事件名,fn:事件处理方法,scrope:范围,其中options的定义比较复杂,可以包含以下属性
      scope {Object} : 处理fn的范围
      delegate {String} : 一个简单选择器(过滤目标或寻找目标的子孙节点)
      stopEvent {Boolean} : 阻止事件,等于preventDefault+stopPropagation
      preventDefault {Boolean} : 阻止默认活动
      stopPropagation {Boolean} : 阻止事件冒泡
      normalized {Boolean} :设为flase将允许浏览器事件替代Ext.EventObject
      delay {Number} : 延时多少毫秒后发生
      single {Boolean} : 只运行一次
      buffer {Number} : 在Ext.util.DelayedTask中预定事件
      当然,还可能自定义参数以传入function


      alignTo( Mixed element, String position, [Array offsets], [Boolean/Object animate] ) : Ext.Element
      将el对齐到element,positon,指示对齐的位置,可选以下定义
      tl     左上角(默认)
      t      上居中
      tr     右上角
      l      左边界的中央
      c      居中
      r      右边界的中央
      bl     左下角
      b      下居中
      br     右下角
      position还可以使用?约束移动不能超出窗口
      offsets 偏移量,以象素为单位
      animate 详见animate定义

      例:div1.alignTo('div2','c-bl?',[20,0],true);
      采用默认动画将div1的最中央对齐到div2的左下角,并右移20个象素,且不能超出窗口


      anchorTo( Mixed element, String position, [Array offsets], [Boolean/Object animate], [Boolean/Number monitorScroll], Function callback ) : Ext.Element
      功能和alignTo类似,只是当窗口重定义大小的时候也会引发重对齐事件
      monitorScroll参数说明是否需要监视滚动条行为,如果定义为数值则是定义的延时,单位为毫秒,默认是50ms,
      callback定义了animate完成后的回叫方法

      animate( Object args, [Float duration], [Function onComplete], [String easing], [String animType] ) : Ext.Element
      执行动画.
      args:目标
      duration:时间间隔.默认是0.35
      Function:完成后的回叫方法
      easing:行为方法 默认值是:easeOut,可选值在ext_base中找到,但没有说明,以下内容从yahoo ui中找到的
      easeNone:匀速
      easeIn:开始慢且加速
      easeOut:开始快且减速
      easeBoth:开始慢且减速
      easeInStrong:开始慢且加速,t的四次方
      easeOutStrong:开始快且减速,t的四次方
      easeBothStrong:开始慢且减速,t的四次方
      elasticIn:
      elasticOut:
      elasticBoth:
      backIn:
      backOut:
      backBoth:
      bounceIn:
      bounceOut:
      bounceBoth:
      太多,慢慢体会吧
      animType:定义动画类型,默认值run 可选值:color/motion/scroll


      appendChild( String/HTMLElement/Array/Element/CompositeElement el ) : Ext.Element
      添加子元素el(el须已存在)

      appendTo( Mixed el ) : Ext.Element
      将当前元素添加到el

      applyStyles( String/Object/Function styles ) : Ext.Element
      应用样式,styles是"width:100px"这样的字符串或{width:"100px"}这样的对象,function是指返回这样的字串和对象的函数,这是一个没有用的批示,因为任何传参的地方都可以是返回要求类型的function.另见setStyle

      autoHeight( [Boolean animate], [Float duration], [Function onComplete], [String easing] ) : Ext.Element
      自适应高度,参数都是老相识了,惟一需要注意的是这个方法使用了setTimeout,高度不会马上变更

      blur() : Ext.Element
      失去焦点,忽略所有的异常

      boxWrap( [String class] ) : Ext.Element
      用一个指定样式class的div将当前元素包含起来,class默认值为x-box

      center( [Mixed centerIn] ) : void
      alignTo的简华版.相当于alignTo(centerIn || document, 'c-c'),当前元素的中心对齐到centerIn元素的中心

      child( String selector, [Boolean returnDom] ) : HTMLElement/Ext.Element
      依selector选择子孙节点,依returnDom不同批示返回html元素还是ext元素,未定义或false时返回Ext.Element

      clean( [Boolean forceReclean] ) : void
      清除无用的空白文本节点(我喜欢这个想法)

      clearOpacity() : Ext.Element
      清除当前元素样式中不通用元素,清除ie中的filter,清除FF中的opacity/-moz-opacity/-khtml-opacity

      clearPositioning( [String value] ) : Ext.Element
       清除定位,恢复到默认值,相当于
       this.setStyle({"left": value,"right": value,"top": value,"bottom": value,"z-index": "","position" : "static"});

      clip() : Ext.Element
      裁剪溢出部分,用unclip()恢复

      contains( HTMLElement/String el ) : Boolean
      当前元素中是否存在el

      createChild( Object config, [HTMLElement insertBefore], [Boolean returnDom] ) : Ext.Element
      创建一个新的子节点
      config :DomHelper元素对象,如果没有特别指明tag,将使用div做默认tag,详情参见DomHelper,如果未定义insertBefore,则追加

      createProxy( String/Object config, [String/HTMLElement renderTo], [Boolean matchBox] ) : Ext.Element
      创建一个代理元素
      config:代理元素的类名或DomHelper config对象
      renderTo:将要绘制代理元素的html element或id
      matchBox:是否对齐

      createShim() : Ext.Element
      在当前元素之前创建一个classname为ext-shim的iframe,有什么用?

      down( String selector, [Boolean returnDom] ) : HTMLElement/Ext.Element
      通过样式选择器selector选择子孙节点

      enableDisplayMode( [String display] ) : Ext.Element
      setVisibilityMode的简便方法

      findParent( String selector, [Number/Mixed maxDepth], [Boolean returnEl] ) : HTMLElement
      通过简单选择器selector寻找祖先节点 ,直到maxDepth(元素maxDepth默认为10,也可以是指定的DOM 节点),找不到返回null

      findParentNode( String selector, [Number/Mixed maxDepth], [Boolean returnEl] ) : HTMLElement
      从父元素开始使用简单选择器selector选择DOM节点

      first( [String selector], [Boolean returnDom] ) : Ext.Element/HTMLElement
      得到第一个符合selector条件的子节点,跳过文本节点

      focus() : Ext.Element
      得到焦点

      getAlignToXY( Mixed element, String position, [Array offsets] ) : Array
      得到当前元素按position规则对齐到element时的XY坐标值 position/offsets参数参见alignTo方法

      getAnchorXY( [String anchor], [Object size], [Boolean local] ) : Array
      得到当前元素锚点指定的坐标值 anchor定义参见alignTo方法,默认为c

      getAttributeNS( String namespace, String name ) : String
      得到使用了命名空间namespace的属性name之值,

      getBorderWidth( String side ) : Number
      得到side指定的边框之和,side可以是t, l, r, b或他们的任意组合,比如getBorderWidth("lr")就是得到左边框和右边框之和

      getBottom( Boolean local ) : Number
      得到当前元素的底部纵坐标,元素纵坐标+元素高度

      getBox( [Boolean contentBox], [Boolean local] ) : Object
      得到当前元素的box对象:{x,y,width,height}

      getCenterXY() : Array
      如果当前元素要居中对齐时的横纵坐标值,等价getAlignToXY(document, 'c-c')

      getColor( String attr, String defaultValue, [String prefix] ) : void
      得到当前元素指定attr的颜色值,如果没指定,返回defualtValue,比较郁闷的是明明不是void为什么api中批示是一个void?应该是个字符串

      getComputedHeight() : Number
      得到计算过的高度,得到offsetHeight或css中定义的height值之一,如果使用了padding/borders,也会计算进去

      getComputedWidth() : Number
      见getComputedHeight

      getFrameWidth( String sides ) : Number
      得到sides定义的border宽度和padding定义的宽度之和,side定义见getBorderWidth

      getHeight( [Boolean contentHeight] ) : Number
      返回元素的offsetHeight

      getLeft( Boolean local ) : Number
      得到横坐标

      getMargins( [String sides] ) : Object/Number
      如果没有定义sides,则返回一个含有{left,top,width,height}对象,反之返回side指定的宽度,side定义见getBorderWidth

      getOffsetsTo( Mixed element ) : Array
      计算从element到当前元素的偏移量

      getPadding( String side ) : Number
      得到由side指定的padding之和

      getPositioning() : Object
      得到当前元素的位置信息 返回含以下属性的对象{position,left,right,top,bottom,z-index}

      getRegion() : Region
      得到当前元素的区域信息 返回含有以下属性的Ext.lib.Region对象{top, left, bottom, right}

      getRight( Boolean local ) : Number
      右边界值

      getScroll() : Object
      得到一个批示滚动条位置的对象{left, top}

      getSize( [Boolean contentSize] ) : Object
      得到宽度和高度组成的对象信息{width,height}

      getStyle( String property ) : String
      得到指定的样式值 getStyles简化版

      getStyles( String style1, String style2, String etc. ) : Object
      得到由参数组成的对象
       例:el.getStyles('color', 'font-size', 'width')
       可能返回 {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}

      getTop( Boolean local ) : Number
      得到顶点纵坐 标

      getUpdater() : Ext.Updater
      得到当前元素的Updater对象,参见Ext.Updater类

      getValue( Boolean asNumber ) : String/Number
      得到value属性的值

      getViewSize() : Object
      得到clientHeight和clientWidth信息给成的对象{width,height}

      getWidth( [Boolean contentWidth] ) : Number
      ..这样的方法真多

      getX() : Number
      getXY() : Array
      getY() : Array
      得到页面偏移量,也就是绝对坐标

      hasClass( String className ) : Boolean
      样式类className 存在于当前元素的dom 节点中

      hide( [Boolean/Object animate] ) : Ext.Element
      隐藏当前元素

      hover( Function overFn, Function outFn, [Object scope] ) : Ext.Element
      设置鼠标移入移出事件

      initDD( String group, Object config, Object overrides ) : Ext.dd.DD
      initDDProxy( String group, Object config, Object overrides ) : Ext.dd.DDProxy
      initDDTarget( String group, Object config, Object overrides ) : Ext.dd.DDTarget
      这个要放到 Ext.dd去专门搞了,用于拖曳

      insertAfter( Mixed el ) : Ext.Element
      insertBefore( Mixed el ) : Ext.Element
      insertFirst( Mixed/Object el ) : Ext.Element
      在DOM中el元素之前之后...插入当前元素

      insertHtml( String where, String html, Boolean returnEl )
      插入html内容 where 可选beforeBegin, afterBegin, beforeEnd, afterEnd

      insertSibling( Mixed/Object/Array el, [String where], [Boolean returnDom] ) :
      插入或创建el做为当前元素的兄弟节点,where可选before/after,默认为before

      is( String selector ) : Boolean
      验证当前节点是否匹配简单选择器selector

      isBorderBox()
      测试不同的样式规则以决定当前元素是否使用一个有边框的盒子

      isDisplayed() : Boolean
      只要不是指定display属性none都会返回真

      isMasked() : Boolean
      仅有当前元素有mask并且可见时为真,mask译为蒙片?就是有些输入框没得到值之前会有一行模糊的提示的那种东西

      isScrollable() : Boolean
      可以滚动?

      isVisible( [Boolean deep] ) : Boolean
      可见?

      last( [String selector], [Boolean returnDom] ) : Ext.Element/HTMLElement
      见first

      load( String/Function url, [String/Object params], [Function callback], [Boolean discardUrl] ) : Ext.Element
      直接应用当前updater的update方法

      mask( [String msg], [String msgCls] ) : Element
      为当前对象创建蒙片

      move( String direction, Number distance, [Boolean/Object animate] ) : Ext.Element
      相前元素相对于当前位置移动,
      direction批示方向可能的值是"l","left" - "r","right" - "t","top","up" - "b","bottom","down".
      distance,指示要移动的距离,以像素为单位

      moveTo( Number x, Number y, [Boolean/Object animate] ) : Ext.Element
      称动到指定的位置

      next( [String selector], [Boolean returnDom] ) : Ext.Element/HTMLElement
      下一个符合selector的兄弟节点,

      on( String eventName, Function fn, [Object scope], [Object options] ) : void
      详见addListener

      position( [String pos], [Number zIndex], [Number x], [Number y] ) : void
      初始化当前元素的位置 pos可选择relative/absolute/fixed

      prev( [String selector], [Boolean returnDom] ) : Ext.Element/HTMLElement
      前一个符合selector的兄弟节点

      query( String selector ) : Array
      通过样式选择器选择子节点

      radioClass( String/Array className ) : Ext.Element
      添加样式或样式数组到当前元素,并移除兄弟节点中的指定样式

      relayEvent( String eventName, Object object ) : void
      将当前元素的eventName事件同时转发给object对象

      remove() : void
      从当前DOM中删除元素,并从缓存中移除

      removeAllListeners() : Ext.Element
      移除所有的侦听者

      removeClass( String/Array className ) : Ext.Element
      移除样式类

      removeListener( String eventName, Function fn ) : Ext.Element
      移除事件eventName的fn侦听器

      repaint() : Ext.Element
      强制浏览器重绘当前元素

      replace( Mixed el ) : Ext.Element
      用当前元素替换el

      replaceClass( String oldClassName, String newClassName ) : Ext.Element
      替换样式类

      replaceWith( Mixed/Object el ) : Ext.Element
      用el替换当前元素

      scroll( String direction, Number distance, [Boolean/Object animate] ) : Boolean
      滚动,scroll会保证元素不会越界,direction和distance参数见move

      scrollIntoView( [Mixed container], [Boolean hscroll] ) : Ext.Element
      滚动到container内的视图

      scrollTo( String side, Number value, [Boolean/Object animate] ) : Element
      基本与scroll方法相同,但不保证元素不越界

      select( String selector, [Boolean unique] ) :
      与query不同的是,通过样式选择器selector,select方法会返回一个复合元素对象(CompositeElement)或CompositeElementLite,

      set( Object o, [Boolean useSet] ) : Ext.Element
      设置属性,例
      el.set({width:'200px',height:'200px'});

      setBottom( String bottom ) : Ext.Element
      setLeft( String left ) : Ext.Element
      setRight( String right ) : Ext.Element
      setTop( String top ) : Ext.Element
      setLeftTop( String left, String top ) : Ext.Element
      设置css 对象的属性值

      setBounds( Number x, Number y, Number width, Number height, [Boolean/Object animate] ) : Ext.Element
      马上改变当前元素的位置和尺寸

      setBox( Object box, [Boolean adjust], [Boolean/Object animate] ) : Ext.Element
      为当前元素设置一个盒子box:{x, y, width, height},adjust指示是否马上调整尺寸

      setDisplayed( Boolean value ) : Ext.Element
      设置可见性

      setHeight( Number height, [Boolean/Object animate] ) : Ext.Element
      setWidth( Number width, [Boolean/Object animate] ) : Ext.Element
      setSize( Number width, Number height, [Boolean/Object animate] ) : Ext.Element
      设置高度和宽度

      setLocation( Number x, Number y, [Boolean/Object animate] ) : Ext.Element
      设置当前元素相对于页面的横纵坐标

      setOpacity( Float opacity, [Boolean/Object animate] ) : Ext.Element
      设置透明度,opacity为1完全不透明,0完全透明

      setPositioning( Object posCfg ) : Ext.Element
      为当前元素指定位置信息,参数posCfg参见getPositioning说明

      setRegion( Ext.lib.Region region, [Boolean/Object animate] ) : Ext.Element
      为当前元素指定区域信息 region定义 见getRegion

      setStyle( String/Object property, [String value] ) : Ext.Element
      设置样式

      setVisibilityMode( visMode Element.VISIBILITY ) : Ext.Element
      指示是使用Element.VISIBILITY还是Element.DISPLAY属性来定义可见性

      setVisible( Boolean visible, [Boolean/Object animate] ) : Ext.Element
      设置可见性


      setX( Number The, [Boolean/Object animate] ) : Ext.Element
      setXY( Array pos, [Boolean/Object animate] ) : Ext.Element
      setY( Number The, [Boolean/Object animate] ) : Ext.Element
      设置当前元素相对于page的位置

      show( [Boolean/Object animate] ) : Ext.Element
      显示当前元素

      swallowEvent( String eventName, [Boolean preventDefault] ) : Ext.Element
      阻止eventName事件冒泡,并视preventDefault阻断默认行为

      toggle( [Boolean/Object animate] ) : Ext.Element
      切换元素的visibility 或display属性,依赖于setVisibilityMode设定的

      toggleClass( String className ) : Ext.Element
      如果样式名存在于当前元素对应的dom 节点,移除,反之应用

      translatePoints( Number/Array x, Number y ) : Object
      返回一个{left,top}结构

      un( String eventName, Function fn ) : Ext.Element
      解除事件侦听,参见   removeListener

      unclip() : Ext.Element
      见clip;

      unmask() : void
      见mask;

      unselectable(): Ext.Element
      禁止文本选择

      up( String selector, [Number/Mixed maxDepth] ) : Ext.Element
      通过样式选择器selector选择祖先节点

      update( String html, [Boolean loadScripts], Function callback ) : Ext.Element
      利用html更新当前节点内容,loadScripts指示html中如果有script,是否需要运行,这是一个innerHTML的一个老老老问题了

      wrap( [Object config], [Boolean returnDom] ) : HTMLElement/Element
      用另一个元素config包含自己
      posted @ 2008-05-23 21:09 meetrice 阅读(242) 评论(0) 编辑
      Array类
      indexOf( Object o ) : Number
      object是否在数组中,找不到返回-1;找到返回位置
      remove( Object o ) : Array
      从数组中删除指定的对象object,如果找不到object则数组无变化

      Number类
      constrain( Number min, Number max ) : Number
      检查数值是否介于min与max之间, 如果大于max 返回max,如果小于min返回min, 否则返回当前值

      String类
      escape( String string ) : String
      将string中的'和\替换为\' \\

      format( String string, String value1, String value2 ) : String
      格式化字符串,例:
      var cls = 'my-class', text = 'Some text';
      var s = String.format('<div class="{0}">{1}</div>', cls, text);// 结果 <div class="my-class">Some text</div>

      leftPad( String string, Number size, [String char] ) : String
      以char将string补齐为size长度,char默认定义空格

      toggle( String value, String other ) : String
      交换值,如果当前值等于value,则被赋值other,反之等于value,例:
      sort = sort.toggle('ASC', 'DESC');

      trim() : String
      去除开头或结尾多余的空格


      Date类
      Date.parseDate( String input, String format ) : Date
      将字符串string依指定的格式format转换为时间,其中格式定义详见format方法
      例:dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d h:i:s A" );


      add( String interval, Number value ) : Date
      增加时间段,String interval在Data类中已定义
      Date.MILLI = "ms";
      Date.SECOND = "s";
      Date.MINUTE = "mi";
      Date.HOUR = "h";
      Date.DAY = "d";
      Date.MONTH = "mo";
      Date.YEAR = "y";
      例var dt2 = new Date('10/1/2006').add(Date.DAY, -5);

      between( Date start, Date end ) : Boolean
      是否在两个指定的时间之间

      clearTime( Boolean clone ) : Date
      清除时间信息,如果clone为真,则克隆自已并返回新Date,本身的值并不改变,反之则修改自身的值

      clone() : Date
      克隆

      format( String format ) : String
      格式化时间
      d     两位数的日期                01 至 31
      D     三字母的星期名                Mon 至 Sun
      j     一位数的日期                1 至 31
      l     完整的星期名                Sunday 至 Saturday
      S     日期的英文顺序刻词尾,两个字符        st, nd, rd or th.
      w     一周中的第几天                0 (星期天) 至 6 (星期六)
      z     一年中的第几天                0 至 364 (闰年365 )
      W     ISO-8601 星期数, 周一算一个星期的开始    1 至 53
      F     月的完整英文名                January 至 December
      m     月,以0前导                01 至 12
      M     三字母的简写月名                Jan 至 Dec
      n     月                    1 至 12
      t     本月有多少天                28 至 31
      L     是否闰年                    1/0
      Y     完整的年份                例: 1999 或 2003
      y     年的后两位                例: 99 或 03
      a     上午/下午小写                am 或 pm
      A     上午/下午大写                AM 或 PM
      g     小时/12小时制                1 至 12
      G     小时/24小时制                0 至 23
      h     小时/12小时制                01 至 12
      H     小时/24小时制                00 至 23
      i     分钟                    00 至 59
      s     秒                    00 至 59
      u     毫秒                    001 至 999
      O     时区,与格林威治标准时间之差        例: +0200
      T     时区简写                    例: EST, MDT ...
      Z     时区间距                    -43200 至 50400
      其中Date类内置了几种格式
      Date.patterns = {
          ISO8601Long:"Y-m-d H:i:s",
          ISO8601Short:"Y-m-d",
          ShortDate: "n/j/Y",
          LongDate: "l, F d, Y",
          FullDateTime: "l, F d, Y g:i:s A",
          MonthDay: "F d",
          ShortTime: "g:i A",
          LongTime: "g:i:s A",
          SortableDateTime: "Y-m-d\\TH:i:s",
          UniversalSortableDateTime: "Y-m-d H:i:sO",
          YearMonth: "F, Y"
      };
      当然ISO8601Long和ISO8601Short还是非常招人喜欢的
      例:
      dt.format(Date.patterns.ISO8601Long);
      dt.format('Y-m-d H:i:s');
       
      getDayOfYear() : Number
      一年中的第几天,从0开始

      getDaysInMonth() : Number
      本月有多少天,

      getElapsed( [Date date] ) : Number
      当前日期对象与date之间相差的毫秒数

      getFirstDateOfMonth() : Date
      本月的第一天

      getFirstDayOfMonth() : Number
      本月第一天是星期几

      getGMTOffset() : String
      时区信息(见格式定义中的'O')
      getFirstDateOfMonth() : Date
      本月最后一天
       
      getFirstDayOfMonth() : Number
      本月最后一天是星期几

      getSuffix() : String
      日期后导符(见格式定义中的S)

      getTimezone() : String
      时区(见T)

      getWeekOfYear() : Number
      一年中的第几周(见W)

      isLeapYear() : Boolean
      是否闰年


      Function类
      createCallback(/*args...*/) : Function
      创建回叫方法

      createDelegate( [Object obj], [Array args], [Boolean/Number appendArgs] ) :
      创建委托
      这两个记法除了传参方式不同,看不出有什么差异都是调用method.apply,createCallback可以看作一个简化版的createDelegate
      createCallback==>return method.apply(window, args);
      createDelegate==>return method.apply(obj || window, callArgs);
      前者参数比较简单,直接传过去了,后者的规则比较复杂点,如果appendArgs为真,args将附加在参数列表之后,如果是数值,args将在参数列表的appendargs位置插入,其它情况下原参将不起作用
      例:
      var fn = func1.createDelegate(scope, [arg1,arg2], true) 
      //fn(a,b,c) === scope.func1(a,b,c,arg1,arg2); 
      var fn = func1.createDelegate(scope, [arg1,arg2]) 
      //fn(a,b,c) === scope.func1(arg1,arg2); 
      var fn = func1.createDelegate(scope, [arg1,arg2], 1) 
      //fn(a,b,c) === scope.func1(a,arg1,arg2,b,c); 
      var fn = func1.createCallback(arg1, arg2); 
      //fn() === func1(arg1, arg2) 


      createCallback : function(/*args...*/) 


      createInterceptor( Function fcn, [Object scope] ) : Function
      创建阻断方法,如果fcn返回false,原方法将不会被执行

      createSequence( Function fcn, [Object scope] ) : Function
      创建组合方法,执行原方法+fcn

      defer( Number millis, [Object obj], [Array args], [Boolean/Number appendArgs] ):Number
      定时执行,隔millis毫秒后执行原方法

       

      发表于 @ 2007年11月24日 17:30:00|评论(3 )|编辑

      旧一篇: EXT核心API详解(一)-Ext

      免费做项目,满意后试用!
      传智播客 免费做项目,满意后试用!
      专家课堂:工作流之JBPM项目实作
      传智播客 专家课堂:工作流之JBPM项目实作

      评论

      #wangxin0072000 发表于2007-12-06 11:33:01  IP: 203.86.61.*
      后续能不能增加一些如何扩展Ext组件的文章。
      另外,对于这一篇中最后章节中关于如何创建回调函数还是不太明白,能提供一些例子吗?
      #blackant2 发表于2007-12-07 09:59:31  IP: 59.173.7.*
      //首先谢谢你对本blog的关心,感动中,半年来第一个
      //言归正传,首先来看看 createCallback/createDelegate的实现,都很简单
      //核心的都只有一句return method.apply(window, args);
      //和 return method.apply(obj || window, callArgs);
      createCallback : function(/*args...*/){
      // make args available, in function below
      var args = arguments;
      var method = this;
      return function() {
      return method.apply(window, args);
      };
      },

      createDelegate : function(obj, args, appendArgs){
      var method = this;
      return function() {
      var callArgs = args || arguments;
      if(appendArgs === true){
      callArgs = Array.prototype.slice.call(arguments, 0);
      callArgs = callArgs.concat(args);
      }else if(typeof appendArgs == "number"){
      callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
      var applyArgs = [appendArgs, 0].concat(args); // create method call params
      Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
      }
      return method.apply(obj || window, callArgs);
      };
      },

      //从上面我们看出,它的功能很简单一点的说就是做一件本来不能做到的事情
      //当然自己无力完成所以委托给别人来做,我们再来看看简单的应用
      Ext.onReady(function(){
      Ext.QuickTips.init()
      var myclass=new Object();
      #blackant2 发表于2007-12-07 10:00:39  IP: 59.173.7.*
      //不好意思,一次帖不远,再来一次
      //从上面我们看出,它的功能很简单一点的说就是做一件本来不能做到的事情
      //当然自己无力完成所以委托给别人来做,我们再来看看简单的应用
      Ext.onReady(function(){
      Ext.QuickTips.init()
      var myclass=new Object();
      //myclass并没有alert方法,我们也不打算为它写一个alert方法
      //我们希望它和window.alert有一样的行为,所以我们委托window来做
      myclass.alert=window.alert.createDelegate(window);
      //我们还希望他有个更漂亮的show方法和Ext.MessageBox的show功能一样
      //所以我们又得委托给Ext.MessageBox来做这事了
      myclass.show=Ext.MessageBox.show.createDelegate(Ext.MessageBox);
      //我们的myclass也有alert和show方法了
      myclass.alert('alert1');
      myclass.show({title:'title',msg:'message'});
      });
      posted @ 2008-05-23 21:08 meetrice 阅读(257) 评论(0) 编辑
      Ext类
      addBehaviors( Object obj ) : void
      对选择的元素 应用事件侦听器,事件名以@附加在结尾,例如
      addBehaviors({
         // id=foo下所有的a标签加入click事件
         '#foo a@click' : function(e, t){
             // do something
         },
         // 用,分隔多个选择器
         '#foo a, #bar span.some-class@mouseover' : function(){
             // do something
         }
      });


      apply( Object obj, Object config, Object defaults ) : Object
      从config拷贝所有的属性到obj,如果有defaults参数,也将拷贝其属性到obj

      applyIf( Object obj, Object config ) : Object
      从config拷贝所有属性至obj(如果obj未定义相应属性)

      decode(Object obj) : String
      编码一个对象/数组或其它值为一个json格式字符串(支持对象,数组,日期,字符串)

      destroy( Mixed arg1, Mixed (optional), Mixed (optional) ) : void
      尝试去移除每个传入的对象,包括DOM,事件侦听者,并呼叫他们的destroy方法(如果存在)


      each( Array/NodeList/Mixed array, Function fn, Object scope ) : void
      利用array中的每个元素迭代调用fn.直到fn返回假,调用格式fn.call(scope || array[i], array[i], i, array);


      encode(String json) : Object
      将一个json格式字符串反序列化为对象

      escapeRe( String str ) : String
      为字符串正则编码将.在*+?^${}()|[]/\字符前加\

      extend( Object subclass, Object superclass, [Object overrides] ) : void
      从superclass类继承subclass,overrides参数是要重载的方法列表,详见override

      fly( String/HTMLElement el, [String named] ) : Element
      得到全局共享的一个浮动元素el,如果有多个浮动元素可以使用命名以避免潜在的冲突

      get( Mixed el ) : Element
      得到一个Element对象,参数可以是id或DOM节点或已存在的Element对象

      getBody() : Element
      得到当前文档的body对象

      getCmp( String id ) : Component
      通过id得到一个Component对象


      getDoc() : Element
      得到当前文档

      getDom( Mixed el ) : HTMLElement
      通过id或节点或Element对象返回一个DOM节点


      id( [Mixed el], [String prefix] ) : String
      为对象el生成一个惟一id,如果对象本身已有id,将不会被改变(可以使用前导符prefix)


      isEmpty( Mixed value, [Boolean allowBlank] ) : Boolean
      判断值是否为空,null, undefined或空字符串将返回真,如果allowBlank定义为真,空字符串将不被视为空

      namespace( String namespace1, String namespace2, String etc ) : void
      创建一个命名空间,例
      Ext.namespace('Company', 'Company.data');
      Company.Widget = function() { ... }
      Company.data.CustomStore = function(config) { ... }

      num( Mixed value, Number defaultValue ) : Number
      将value转为数值,如果value不是合法的数值类型,将返回defaultValue,其实defaultValue并不一定要求是数值类型,只要你愿意


      onReady( Function fn, Object scope, boolean override ) : void
      当文档准备好了之后引发fn,发生在page的onload事件之前,并且图片此时都还没有载入,scope定义执有者,override定义scope是否有默认的选择


      override( Object origclass, Object overrides ) : void
      利用overrides重写origclass的方法,例
      Ext.override(MyClass, {
          newMethod1: function(){
              // etc.
          },
          newMethod2: function(foo){
              // etc.
          }
      });

      query( String path, [Node root] ) : Array
      通过path,在root中选择节点数组,path可以是以下四种选择器之一
      [元素选择器] 例:
      * 任意节点
      E 一个E标签元素
      E F 祖先节点为E的F节点
      E > F 或 E/F 父节点为E的F节点
      E + F 前一个兄弟节点为E的F节点
      E ~ F 前面的兄弟节点中有E的F节点
      [属性选择器] 例:
      E[foo] 有foo属性的E节点
      E[foo=bar] 有foo属性值为bar的E节点
      E[foo^=bar] foo属性以bar开始的E节点
      E[foo$=bar] foo属性以bar结尾的E节点
      E[foo*=bar] foo属性中有bar字符串的E节点
      E[foo%=2]  foo属性能被2整除的E节点
      E[foo!=bar] foo属性值不为bar的E节点
      [伪类选择器] 例:
      E:first-child E节点是父节点中第一个子节点
      E:last-child E节点是父节点中最后一个子节点
      E:nth-child(n) E是父节点中每n个节点
      E:nth-child(odd) E是父节点中的奇数节点
      E:nth-child(even) E是父节点中的偶数节点
      E:only-child E是父节点中惟一的子节点
      E:checked checked属性为真的节点
      E:first 子孙节点中的第一个E节点
      E:last  子孙节点中的最后一个E节点
      E:nth(n) 子孙节点中的第n个E节点
      E:odd E:nth-child(odd)的简写
      E:even E:nth-child(even)的简写
      E:contains(foo)  innerHTML属性中含有foo的E节点
      E:nodeValue(foo) E节点中包含一个值为foo的文本节点
      E:not(S) 不匹配简单选择器S的E节点
      E:has(S) 有能匹配简单选择器S的子节点的E节点
      E:next(S) 下一个兄弟节匹配简单选择器S的E节点
      E:prev(S) 前一个兄弟节匹配简单选择器S的E节点
      type( Mixed object ) : String
      判断对象类型,如果不是下列值之一将返回false
      [样式选择器] 例:
      E{display=none} display属性值为none的E节点
      E{display^=none} display属性值以none开始的E节点
      E{display$=none} display属性值以none结束的E节点
      E{display*=none} display属性值含有none子字串的E节点
      E{display%=2} display属性值能被2整除的E节点
      E{display!=none} display属性值不等于none的E节点


      select( String/Array selector, [Boolean unique], [HTMLElement/String root] ) :CompositeElementLite/CompositeElement
      在root内通过样式选择器或元素数组selector选择元素或元素列表,unique指示是否只选择惟一值

      urlDecode( String string, [Boolean overwrite] ) : Object
      将url格式字符串string解码为json对象,overwrite参数指示是否不重写已存在的对象,例
      Ext.urlDecode("foo=1&bar=2"); //返回 {foo: 1, bar: 2}
      Ext.urlDecode("foo=1&bar=2&bar=3&bar=4"); //返回 {foo: 1, bar: 4}.
      Ext.urlDecode("foo=1&bar=2&bar=3&bar=4", true); //返回 {foo: 1, bar: [2, 3, 4]}.

      urlEncode( Object o ) : String
      将json对象编码为url格式字符串,参见urlDecode
           
      type( Mixed object ) : String
      得到object类型,如果不为以下列举值之一则返回false
      string/number/boolean/function/object/array/regexp/element/nodelist/textnode/whitespace
      posted @ 2008-05-23 21:08 meetrice 阅读(177) 评论(0) 编辑
      posted @ 2008-05-23 21:05 meetrice 阅读(531) 评论(0) 编辑
      Ext 2.0的API包含许多的方法(函数)、属性和配置项,涵盖的面非常大,要全部列出几乎是不可能的。虽然API文档是童叟无欺精心打造的,但实际开发中,若果能够像其它语言Java和C#那样地支持JavaScript代码提示,那就更好啦。可喜的是,有若干的开发环境(IDE)和插件能够支持--并且是直接支持Ext 2.0。 Aptana Studio 一谈到JavaScript的开发工具,就不得不提Aptana了。就我实际工作来说,每天都用它来完成Adobe AIR的工作。但是Aptana当前捆绑的Ext的版本有些旧(1.1的),下面就介绍一个插件的安装方法,让Aptana支持到2.0(由Markus Schmidleitner提供,用起来还不错):
      1.下载并安装Aptana Studio; 2.打开你的Aptana程序目录(我这儿是C:\Aptana),复制jar格式的文件到plugins目录; 3.重启Aptana; 4.进入Window -> Preferences -> Aptana -> Editors -> JavaScript -> Code Assist选择Ext 2.0(或要反选Ext.1.1)。

      Aptana Studio with Ext 2.0 code assist

      Spket Eclipse插件与IDE Spket IDE是目前支持Ext 2.0最为出色的IDE。 它采用.jsb project file 文件并将继承于基类和所有文档的内容嵌入到生成代码提示的Script doc中。 由于Spket只是一个单纯的编辑器,没有其它格式的支持(如CSS),所以我的做法是用它的Eclipse插件形式,安装到Aptana。安装办法如下:
      1.下载安装Aptana Studio(包含有Eclipse); 2.启动Aptana并打开程序菜单到:Help → Software Updates → Find and Install… → Search for new features to install → New remote site… 3.名称: "Spket",地址URL是http://www.spket.com/update/ 4.重启Aptana; 5.观看一下这个SketIDE的教程,看看Ext代码提示的功能有多省事(你可以修改/src/ext.jsb 保持最新版的Ext),基本步骤如下:
      1. Window → Preferences → Spket → JavaScript Profiles → New ;
      2. 输入"ExtJS"点击OK;
      3. 选择"ExtJS" 并点击"Add Library"然后在下拉条中选取"ExtJS";
      4. 选择 "ExtJS"并点击"Add File",然后在你的./ext-2.x/source目录中选取"ext.jsb" 文件;
      5. 设置新的ExtJS Profile,选中并点击"JavaScript Profiles" 对话框右手边的"Defalut"按钮;
      6. 重启Aptana;
      7. 创建新的JS文件并输入: Ext这样就可设置Ext Code代码自动完成的功能。
      由于你是在Aptana中安装插件的,Aptana还是你默认的JS编辑器,所以要试用Spket,你要在那个文件上选中"Open with"-> Spket JavaScript Editor 。

      Spket in Aptana with full documentation and code assist

      Komodo Edit Komodo Edit为众多格式文件提供支持,包括Perl、PHP、Python、Ruby和Tcl。亦支持浏览器方面的代码包括有JavaScript、CSS、HTML和XML。Windows、Mac Os和Linux平台都可用。 安装Ext支持下的Komodo:
      1.下载和安装Komodo Edit; 2.下载API catalog; 3.进入Edit -> Preferences -> Code Intelligence 并选择位于"API Catalog"下方的按钮"Add an API catalog" ; 4.选择刚才下载的ExtJS API catKomodo Editalog CIX 。

      Komodo with Ext JS code intelligence

      Dreamweaver 对于Dreamweaver的用户,有两种可用的插件SpketDW(Dreamweaver 2004或新版)和SpketDWCS(Dreamweaver CS3)。两者都是Spket团队开发的(刚才提及的),因此也同样精确和出色。另外Dreamweaver插件的一大特点是很好地支持配置项的代码提示。

      Members code assist

      Config option code assist

      要下载和安装,请浏览他们的站点其它的IDE 还有其它的IDE,像由社区发起的正在工作着的IntelliJ和Visual Studio 2008总结 当工作中需要到Ext 2.0,的确有一些工具能辅助你提升工作

      posted @ 2008-05-23 21:00 meetrice 阅读(658) 评论(0) 编辑

      在开发EXT中,我分别使用了Aptana和Spket


      一、Spket的安装

      1、Plugin:
      最低要求: eclipse平台运行时3.2.x ,
      文件为: spket-1.6.4.1.zip(与别的插件的安装无异,相信不用我多说了吧
      2、Spket IDE:
      最低要求:你需要java 1.5或更高版本运行安装程序,可独立使用(不用装Eclipse
      文件为:spket-1.6.4.1.jar
      安装步骤:1、打开cmd,2、在spket-1.6.4.1.jar文件目录下输入java -jar spket-1.6.4.1.jar
      3、回车(相信你已看到安装画面
      3、Update Site
      这是更新网站,为spket的ide 。
      使用它,打开eclipse的updatemanager (在eclipse下的帮助菜单) ,并新增一个书签为:
      http://www.spket.com/update

      二. Spket的配置与使用

      创建jQuery profile


      • 选择菜单项目中Window > Preferences...
      • 选择spket > javascript Profile页面
      • 点击new...按钮。在名称里面,写入jquery。然后单击确定。
      • 点击Add Library 按钮. 从Library下拉列表中, 选择jquery 。然后单击确定。
      • 点击Add File 按钮, 选择jquery.js 可从jquery.com下载(也可用附件里的)。
      • 选择jQuery profile 按照第3步, 点击Default 按钮把它预设为 default 项. The default profile 也可通过配置每个项目利用 Configure Project Specific Settings... 配置。
      • 点击OK保存preference。

      创建EXT 2.0 profile ,用Spket进行Ext2.0开发

      将以下代码放入文件ext.jsb的标记 </project>之前

      <target name="Ext Base">
      <include name="core\Ext.js" />
      <include name="adapter\yui-bridge.js" />
      <include name="yui\yahoo.js" />
      <include name="yui\dom.js" />
      <include name="yui\event.js" />
      <include name="yui\connection.js" />
      <include name="yui\animation.js" />
      </target>

      1. 选择菜单项目中Window > Preferences...
      2. 选择spket > javascript Profile页面
      3. 点击new...按钮。在名称里面,写入EXT。然后单击确定。
      4. 点击Add Library 按钮. 从Library下拉列表中, 选择EXTJS 。然后单击确定。
      5. 点击Add File 按钮, 选择ext源码里的 ext\source\ext.jsb
      6. 点击OK保存preference。


      接着,你就可以在js代码中自动提示代码



      Ext Theme Builder

      在project目录下,新建一个文件,文件名为ext.theme,打开文件,指定ext的resource文件夹路径,就可以调整ext界面的颜色,效果等,生成自己的css文件




      spket自定义脚本的引用申明及提示

      1. 首先在当前js文件头部使用spket的包含语法引入包含的js:

      /**
      * @include "../js/custom.js"
      */
      2.按 ctrl+click即可打开js申明,或ctrl+/ 自动完成提示
      posted @ 2008-05-23 20:59 meetrice 阅读(152) 评论(0) 编辑

      FireStorm/DAO让Java软件开发工具能借由存取服务导向和对象导向结构的相关数据库产生Business逻辑。通过导入SQL scripts或实时的数据库定义,基于 JDBC/JDO/EJB/Hibernate 等持久层技术,FireStorm可以产生符合Data Access Object(DAO)模式础的持久层代码。

      破解文件下载:http://www.namipan.com/downfile/fscommon.jar/d05c2a276f7ae601992bb7a56de978b44883748f399a0400


      posted @ 2008-05-23 20:59 meetrice 阅读(200) 评论(0) 编辑

      ajax的js开发的目录规范 (目录框架下载)

      ajax的js开发的目录规范:
      ├──framework //存放RIA框架资源
      │ ├──ext2.0.2
      │ └──dojo1.1.0
      ├──modules //存放项目模
      │ ├──oa-admin
      │ ├──oa-news
      │ └──upload
      ├──images //存放项目专用图片
      ├──css //存放项目样式
      ├──widget //存放项目公用组件
      │ └──UploadDialog
      └──request //server端URL或代码
      index.html
      login.html

      ajax模板项目下载:
      http://www.namipan.com/d/ajaxAppSpec.rar/70576f28a6bd4e4609bd670f1b44ca5352b4db026e730300

      posted @ 2008-05-23 20:59 meetrice 阅读(280) 评论(0) 编辑

      1. Ext中常用的类

       I. Ext.data
        Ext.data封装了与数据有关的类。

       II. Ext.data.Store
        Store是数据源的封装。Ext通过Store提供了统一的接口访问不同的数据源,从数组到 ajax数据来源。这种统一的接口,让使用数据的部件更易于设计和使用。在设计使用数据的部件时,只需要关心Store提供的接口,而不需要关心底层数据的来源。数据消费部件与底层数据源的隔离,更有利于扩展新的数据类型,只需要为新的类型添加相应的解释程序即可。
        Store有两个关键的config options:
         a. proxy数据代理,Ext.data.DataProxy。这是store用于管理低层数据的部分。
         b. reader数据读取, Ext.data.DataReader。这是store读取数据的成员,它定义底层数据的结构。
        Store同时支持Inline的数据,用data config option指定。如:
         store: new Ext.data.SimpleStore({
          fields: ['text'],
          expandData: true,
          data : ['目录', '项目', '两者']
         }),

        Store有几个子类:  GroupingStore, JsonStore, SimpleStore

        重要的方法:load

       III. 数据视图类。主要有Ext.DataView,Ext.grid,Ext.form等。

        数据视图类,用可视化的界面显示或操作数据。数据视图类的数据来源是Store,通过这个统一的接口,与不同的数据源结合起来。Store中的数据发生变化时,界面上会反映出来。config option是store。

        Ext.DataView有点特殊,因为这个类没有预定的显示模式,而是需要自己指定显示模板(Ext.XTemplate类,支持简单的模板语言)。其他都差不多。

      3. Viewport
        刚开始使用Ext的时候,Viewport困扰了我很长时间。帮助里找不到太多可用的资料,只能慢慢摸索。
        Viewport采用region定义各Block的显示。看Ext Api Document里的例子,里面都列出来了。刚开始的时候不明白region做什么用的。后来才逐渐明白。其中各个region,只有center是必不可少的。

      4. Panel
        刚开始,看一个例子,用Panel做Header,也试着做了个,发现Panel里自己的元素下面有一个方框(border:true时),怎么也去不掉。看代码,发现自己的元素在Panel元素内部前面部分,后面有一个"bwrap"区,就是那个框。后来还是参考例子解决问题。有三个条件:
        a. panel的layout指定为:anchor
        b. 自己的元素放在panel的items里定义
        c. 自己的元素,指定xtype为box
        看例子:

         new Ext.Panel{
          border: false,
          layout:'anchor',
          region:'north',
          cls: 'twHeader',
          height:60,
          items: [{ //放到items里定义
           xtype: "box", //这里指定类型为box
           el: "twHeader", //自己的元素ID
           border: true,
           anchor: "an_twHeader"
          }]
         })

      5. Ext的对象,在Render以前与以后行为是不一样的。

        今天程序里用getTopToolbar取顶部工具栏,返回的不是Ext.Toolbar对象,反复检查,都不清楚原因,很是奇怪。后来才发现,对象Render以后,getTopToolbar才是正确的,Render以前,返回值是不对的。

      6.ownerCT:对象的直接父元素

      7. Ext.form.FormPanel对象

       I. submit方法。FormPanel.getForm().submit()方法提前当前的表单。getForm方法返回当前FormPanel的BasicForm,调用BasicForm的submit方法提交表单。submit方法有一些参数,其中success和failure参数分别担定成功和失败时的执行函数。submit方法对返回的数据格式有一定的要求。如果没有指定form的errorReader, Ext就会认为你返回的是一段JSon表达式,会通过Ext.decode去执行它。对这个返回的要求是:要有success数据项,指明调用是否成功。只有一切正常并且success为true时,submit里指定的success函数才会触发,否则是failure被触发。有一个例外,就是当返回是空白时,success函数也会触发。

      8.ComboBox

        name属性存放显示变量名称,其中存放选中行的显示值,一般是代码的含义
        hiddenName属性存放值变量名称,其中存放选中行的内部值,一般是对应的代码
        displayField:ComboBox所用store中,用于显示的field名称,对应name
        valueField:ComboBox所用store中,存放代码值field名称,对应hiddenName
        


      posted @ 2008-05-23 20:59 meetrice 阅读(469) 评论(0) 编辑
      posted @ 2008-05-23 20:57 meetrice 阅读(1014) 评论(0) 编辑
      posted @ 2008-05-23 20:54 meetrice 阅读(643) 评论(0) 编辑
       
      用JSON技术加快AJAX程序开发
      朱先忠 编译
      一、引言
      当微软把ActiveX XMLHTTP对象纳入到JavaScript的Internet Explorer实现中时,它实际上已经为Web应用程序的又一次革命(异步JavaScript+XML,简称AJAX)埋下了“火种”。今天,Firefox,Safari,Opera及其它浏览器都支持XMLHttpRequest对象,正是这些支持最终才导致了诸如colr.org,backpackit.com和maps.google.com等著名网站的产生。尽管这些网站(不止这些)所提供的应用程序运行于一种浏览器中,但是它们在行为和外观上却极类似于传统的桌面应用程序。

      在AJAX技术中,在用户观看并与页面交互的同时(这正相应于AJAX中的“异步”部分),由页面中的JavaScript负责把数据请求发送到一个Web服务器。这些请求只是一些普通的HTTP请求,与浏览器用于页面(连同其中的任何图像,层叠式样表等内容)检索的HTTP完全相同。同时,XMLHttpRequest对象可以用于检索任何类型的数据,而不仅仅是XML类型。例如,JavaScript可以使用XMLHttpRequest来检索一个来自于Web服务器的普通文本文本并且把它的内容显示于一个表单中。
      通过查找位于数据之前的“content-type”头部,XMLHttpRequest对象分析从Web服务器返回的数据的MIME类型。例如,如果这些数据的MIME类型是“text/plain”,那么你可以通过分析XMLHttpRequest对象的responseText属性来存取它;然而,如果其MIME类型为“text/xml”,那么XMLHttpRequest对象必须采取额外的措施:它要在返回的文档对象上运行一个XML分析器内存中构建一棵文档对象模型(DOM)树来描述该文档并且还要使其可用于responseXML属性。然后,你才可以使用JavaScript的标准DOM方法在树中导航并检索元素、属性及位于该DOM树中的其它文本。
      虽然XML是进行数据交换的标准方式,但是通常它不是最好的方式。尽管XML可以把结构和元数据添加到数据上,但是它使用了一种相当繁琐的方式。XML还有一种相对复杂的语法,因而需要一种分析器对之进行专门分析。在JavaScript中,XML必须被分析成一棵以备后用的DOM树。并且,一旦你构建了这棵DOM树,你还必须在其中导航以便创建相应的JavaScript对象或者以其它方式在你的客户端Web应用程序中使用XML数据。
      幸好,你还有另外更好的可选方案。
      二、JSON简介 javascript object notation
      JavaScript对象标志,简称JSON,是一种描述数据的轻量级语法。JSON的优越性基于这样的事实:它本身就是JavaScript语言的一个子集。你会在后面看到这种特征的重要性。首先,让我们比较一下JSON和XML的原始语法。
      XML和JSON都使用结构化方法来标记数据。例如,一个地址簿应用程序可能提供一个Web服务—它将以XML形式生成如下的地址卡片:
      <?xml version='1.0' encoding='UTF-8'?>
      <card>
      <fullname>Sean Kelly</fullname>
      <org>SK Consulting</org>
      <emailaddrs>
      <address type='work'>kelly@seankelly.biz</address>
      <address type='home' pref='1'>kelly@seankelly.tv</address>
      </emailaddrs>
      <telephones>
      <tel type='work' pref='1'>+1 214 555 1212</tel>
      <tel type='fax'>+1 214 555 1213</tel>
      <tel type='mobile'>+1 214 555 1214</tel>
      </telephones>
      <addresses>
      <address type='work' format='us'>1234 Main St
      Springfield, TX 78080-1216</address>
      <address type='home' format='us'>5678 Main St
      Springfield, TX 78080-1316</address>
      </addresses>
      <urls>
      <address type='work'>http://seankelly.biz/</address>
      <address type='home'>http://seankelly.tv/</address>
      </urls>
      </card>
      而使用JSON来表达,上面的形式将变成如下模样:

      {
      "fullname": "Sean Kelly",
      "org": "SK Consulting",
      "emailaddrs": [
      {"type": "work", "value": kelly@seankelly.biz"},
      {"type": "home", "pref": 1, "value": "kelly@seankelly.tv"}
      ],
      "teleph [
      {"type": "work", "pref": 1, "value": "+1 214 555 1212"},
      {"type": "fax", "value": "+1 214 555 1213"},
      {"type": "mobile", "value": "+1 214 555 1214"}
      ],
      "addresses": [
      {"type": "work", "format": "us",
      "value": "1234 Main StnSpringfield, TX 78080-1216"},
      {"type": "home", "format": "us",
      "value": "5678 Main StnSpringfield, TX 78080-1316"}
      ],
      "urls": [
      {"type": "work", "value": "http://seankelly.biz/"},
      {"type": "home", "value": "http://seankelly.tv/"}
      ]
      }
      正如你所见,JSON也提供了一种具有嵌套数据元素的结构,就象XML一样。与XML一样,JSON也是基于文本的,且它们都使用Unicode编码,且其与XML一样具有可读性。主观上来看,JSON更为清晰且冗余更少些。JSON网站提供了对JSON语法的严格描述,只是描述较简短。从总体来看,XML比较适合于标记文档,而JSON却更适于进行数据交换处理。一个JSON文档的每一个实例都负责描述一个对象—具体的描述是通过使用嵌套的对象,数组,字符串,数字,布尔值或null值来实现的。
      上面地址卡例子的JSON版本更为小些,仅占用大约682字节的空间,而XML版本需要744字节空间。当然,这不是什么惊人的节省。其实,JSON的真正优点在于数据分析方面。
      三、JSON与XML数据分析对比
      借助于XMLHttpRequest对象,你可以从自己的基于AJAX的应用程序内部检索XML和JSON文件。典型情况下,你可以使用类似如下的交互:
      var req = new XMLHttpRequest();
      req.open("GET","http://localhost/addr?cardID=32", /*async*/true);
      req. = myHandler;
      req.send(/*no params*/null);
      随着对Web服务器的不断响应,被你传递的处理器函数(在本例中是myHandler)被反复调用,这种特征提供给你一种时机—及早地取消事务,更新一个进度条,等等。通常,你只是在Web请求完成时才采取行动(应用返回的数据)。
      为了处理上面地址卡程序的XML版本,myHandler的编码可以类似如下:
      function myHandler() {
      if (req.readyState == 4 /*完成*/) {
      //用第一个街道地址更新表单中的地址域
      var addrField = document.getElementById('addr');
      var root = req.responseXML;
      var addrsElem = root.getElementsByTagName('addresses')[0];
      var firstAddr = addrsElem.getElementsByTagName('address')[0];
      var addrText = fistAddr.firstChild;
      var addrValue = addrText.nodeValue;
      addrField.value = addrValue;
      }
      }
      注意,你不必自己分析XML文档,分析任务可以由XMLHttpRequest对象为你自动完成。之后,这个XMLHttpRequest对象使得由分析生成的DOM树可应用于responseXML属性中。然后,你可以借助这个responseXML属性并调用getElementsByTagName方法来查找文档中的addresses部分,但仅能使用找到的第一个(其实只有一个)。然后,你再次在找到的address上调用getElementsByTagName方法来查找下一层中的第一个address元素,然后再次使用找到的第一个address……然后,你得到该元素的第一个DOM子结点(它是一个文本结点)并得到该结点的值(它正是你想找的街道地址)。最后,你就可以在表单域中显示它。
      显然,这是一项工作量很大的工作!现在,让我们试用一下JSON:
      function myHandler() {
      if (req.readyState == 4 /*complete*/) {
      var addrField = document.getElementById('addr');
      var card = eval('(' + req.resp + ')');
      addrField.value = card.addresses[0].value;
      }
      }
      你需要做的第一件事情是手工地分析JSON响应。然而,因为JSON是JavaScript的一个子集,所以你可以通过调用eval方法使用JavaScript自己的编译器来完成这些。分析JSON是非常简单的!而且,在产生于JSON中的一个对象中导航与在任何JavaScript对象中导航完全一样。这比在DOM树中导航要容易得多。例如:
      •card.addresses[0].value对应第一条街道地址:“1234 Main Stb &”;
      •card.addresses[0].type对应地址的类型:“work”;
      •card.addresses[1]对应一个家庭地址对象;
      •card.fullname对应卡片名:“Sean Kelly”。
      如果仔细观察,那么你可能注意到,示例程序的XML版本至少要处理包含在文档中的一个对象—根文档元素card。这在JSON版本中是不存在的。为什么?如果你曾开发过存取一个Web服务的JavaScript,那么你就会知道你要从Web服务中取回什么。然而,你可以在JSON中包括下面一种更为简练的形式:
      {"card": {"fullname": ...}}
      通过使用这一技术,你的JSON文件总是以一个对象开头并且用单个命名的属性来标记该对象的“类型”。
      四、JSON的快速可靠性
      JSON能够生成更小的文档,且其在JavaScript脚本中更易于使用。XMLHttpRequest能够为你自动分析XML文档,然而你必须手工分析JSON。这样以来,你可能质疑:分析JSON是否比分析XML更慢?对比JSON,我针对上面的地址卡测试了嵌入到XMLHttpRequest中的XML分析器—通过把这些数据置入上千次的循环中。最终结果表明,分析JSON比分析XML快大约10倍!如果想实现AJAX程序的行为类似于桌面应用程序,那么速度就是一切。很明显,JSON是胜者。
      当然,你不可能一直控制为你的AJAX应用程序产生数据的服务器端。你可以使用一种第三方服务器来处理你的数据,而且让该服务器仅提供XML输出。然而,如果该服务器中恰巧能够提供JSON支持,那么你能否确定并敢于使用这一支持?
      注意,在上面的示例中,你是直接把响应文本传递到一个对eval的调用中。如果你信任并控制了服务器,这是没有问题的;然而,另外一些情况下,一个恶意的服务器有可能给你的浏览器执行带来危险操作。为此,你最好使用一个用JavaScript编写的JSON分析器。幸好,已经存在可用的分析器了。
      谈到分析器,Python迷们可能还没有注意到,JSON不仅是JavaScript的一个子集,而且它还是Python的一个子集。你可以直接在Python中使用JSON,或利用一种安全的JSON分析器。现在,针对于JSON的分析器也大量地存在于其它语言中;你可以参考JSON.org网站来选择使用相应的分析器。
      五、服务器端技术对JSON的支持
      到目前为止,我们一直集中于讨论如何把JSON应用于客户端浏览器上的基于AJAX技术的Web应用程序。当然,Web服务器端必须存在一定的技术支持才能实现首先生成JSON,然后由客户端使用JSON。幸好,基于现有数据结构创建JSON是一件相当直接的事情。另外,一些Web应用程序框架(例如TurboGears)已经自动包括支持JSON输出。
      另外,商业Web服务供应商也都特别关注JSON。Yahoo最近在其Web服务中大量地加入对JSON的支持。Yahoo的多种搜索服务,旅行规划者,del.icio.us和高速公路交通服务都支持JSON输出。无疑,其它一些主要的Web服务供应商也都会逐渐地提供对JSON的支持。
      六、结论
      JSON的基本思想是,把自己实现为JavaScript(和Pyth 2.0开发中XML数据操作的主要替代者。任何开发者,无论是开发标准桌面应用程序还是开发Web应用程序,只要使用XML数据处理,都会欣赏JSON的简易特征。最后,我衷心祝愿JSON能加快你的基于AJAX技术的Web 2.0应用程序的开发。
      posted @ 2008-05-23 16:20 meetrice 阅读(237) 评论(0) 编辑

      javaScript 中的 call() 是一个奇妙的方法,但也是一个让人迷惑的方法,先看一下官方的解释:

      call 方法
      请参阅
      应用于:Function 对象
      要求
      版本 5.5
      调用一个对象的一个方法,以另一个对象替换当前对象。

      call([thisObj[,arg1[, arg2[,   [,.argN]]]]])
      参数
      thisObj
      可选项。将被用作当前对象的对象。
      arg1, arg2, , argN
      可选项。将被传递方法参数序列。
      说明
      call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

      如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

      -------------------------------------------------------------------------------------------
      乍一看,很容易把人看迷胡,先做一些简单的说明
      obj1.method1.call(obj2,argument1,argument2)
      如上,call的作用就是把obj1的方法放到obj2上使用,后面的argument1..这些做为参数传入.

      举一个具体的例子
      function add(a,b)
      {
          alert(a+b);
      }
      function sub(a,b)
      {
          alert(a-b);
      }

      add.call(sub,3,1);

      这个例子中的意思就是用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4); // 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。


      看一个稍微复杂一点的例子

      function Class1()
      {
          this.name = "class1";

          this.showNam = function()
          {
              alert(this.name);
          }
      }

      function Class2()
      {
          this.name = "class2";
      }

      var c1 = new Class1();
      var c2 = new Class2();

      c1.showNam.call(c2);

      注意,call 的意思是把 c1 的方法放到c2上执行,原来c2是没有showNam() 方法,现在是把c1 的showNam()方法放到 c2 上来执行,所以this.name 应该是 class2,执行的结果就是 :alert("class2");

      怎么样,觉得有意思了吧,可以让a对象来执行b对象的方法,这是java程序员所不敢想的。还有更有趣的,可以用 call 来实现继承

      function Class1()
      {
          this.showTxt = function(txt)
          {
              alert(txt);
          }
      }

      function Class2()
      {
          Class1.call(this);
      }

      var c2 = new Class2();

      c2.showTxt("cc");

      这样 Class2 就继承Class1了,Class1.call(this) 的 意思就是使用 Class1 对象代替this对象,那么 Class2 中不就有Class1 的所有属性和方法了吗,c2 对象就能够直接调用Class1 的方法以及属性了,执行结果就是:alert(“cc”);

      对的,就是这样,这就是 javaScript 如何来模拟面向对象中的继承的,还可以实现多重继承。

      function Class10()
      {
          this.showSub = function(a,b)
          {
              alert(a-b);
          }
      }

      function Class11()
      {
          this.showAdd = function(a,b)
          {
              alert(a+b);
          }
      }


      function Class2()
      {
          Class10.call(this);
          Class11.call(this);
      }

      很简单,使用两个 call 就实现多重继承了
      当然,js的继承还有其他方法,例如使用原型链,这个不属于本文的范畴,只是在此说明call 的用法
      说了call ,当然还有 apply,这两个方法基本上是一个意思
      区别在于 call 的第二个参数可以是任意类型,而apply的第二个参数必须是数组,也可以是arguments
      还有 callee,caller,这个和call的 用法就不同了,放到下次讲吧 ,呵呵。

      posted @ 2008-05-23 15:04 meetrice 阅读(344) 评论(0) 编辑
      JavaScript 和 .NET 中的 JavaScript Object Notation (JSON) 简介
       

      Atif Aziz,Scott Mitchell

      2007 年 2 月

      适用于:
      JSON
      Ajax

      摘要:本文 JavaScript Object Notation(或 JSON),即一种开放式和基于文本的数据交换格式,它提供了一种标准数据交换格式,更适用于 Ajax 样式的 Web 应用程序。(打印共 22 页)

      目录

      简介
      了解 JavaScript 中的文字表示法
      比较 JSON 与 XML
      使用 JavaScript 创建和分析 JSON 消息
      在 .NET Framework 中使用 JSON
      结论
      参考资料

      下载本文中所用的源代码

      简介

      在设计要与远程计算机进行通信的应用程序时,必须选择一种数据格式和交换协议。有多种开放式标准方案可供选择,而最理想的选择取决于应用程序需求和已有的功能。例如,基于 SOAP 的 web 服务格式化数据的方式是将 XML 负载封装到 SOAP 信封中。

      XML 对于许多应用场合非常好用,但在另外一些情况下则存在缺陷,使用不太理想。XML 通常使用效果不太理想的领域之一是 Ajax 风格的 web 应用程序。Ajax 是用于构建交互式 web 应用程序的技术,此类应用程序通过使用对 web 服务器的带外轻型调用来代替整页回发,从而提供了更为迅捷的用户体验。这些异步调用通过 JavaScript 在客户端进行初始化,涉及设置数据格式、将其发送到 web 服务器,以及分析和处理返回的数据。大多数浏览器可以构建、发送和分析 XML,而 JavaScript Object Notation(或 JSON)提供了一种适用于 Ajax 风格的 web 应用程序的标准数据交换格式。

      JSON 是一种基于文本的开放式数据交换格式(请参见 RFC 4627)。与 XML 一样,它便于读者阅读、独立于平台,并且具有广泛的可实现性。根据 JSON 标准设置格式的数据是轻型的,可由 JavaScript 实现轻而易举地进行分析,使之成为适用于 Ajax web 应用程序的理想数据交换格式。JSON 主要是一种数据格式,因此它不局限于 Ajax web 应用程序,在任何场合,只要应用程序需要将结构化信息作为文本进行交换或存储,即可使用它。

      本文探讨了 JSON 标准及其与 JavaScript 的关系,并将其与 XML 进行比较。文中讨论了用于 .NET 的开源 JSON 实现 Jayrock,并提供了许多使用 JavaScript 和 C# 创建和分析 JSON 消息的示例。

      了解 JavaScript 中的文字表示法

      在编程语言中,文字用于“从字面上”表达固定值,如常量整数值 4 或字符串“Hello, World”。文字可用在大多数允许使用表达式的语言中,如控制语句的部分条件、调用函数时的输入参数、变量赋值等等。例如,以下 C# 和 Visual Basic 代码使用常量整数值 42 来初始化变量 x

      int x = 42;  // C#
      Dim x As Integer = 42  ' Visual Basic

      不同的编程语言允许使用不同类型的文字。大多数编程语言至少都支持标量类型的文字,如整数、浮点数、字符串和布尔值。对于 JavaScript 来说,有意思的一点是,除了标量类型之外,它还支持结构化类型的文字,如数组和对象。此功能允许在按需要创建和初始化数组及对象时使用简洁的语法。

      JavaScript 中的数组文字由零个或多个表达式组成,每个表达式代表数组的一个元素。数组元素括在方括号内 ([]),并以逗号分隔。以下示例使用具有七大洲名称的七个字符串元素来“从字面上”定义数组:

      var continents = ["Europe", "Asia", "Australia", "Antarctica", "North
       America", "South America", "Africa"];
      alert(continents[0] + " is one of the " + continents.length + "
       continents.");

      设想在没有文字表示法的 JavaScript 中创建和初始化数组的情形,将此与之比较:

      var continents = new Array();
      continents[0] = "Europe";
      continents[1] = "Asia";
      continents[2] = "Australia";
      continents[3] = "Antarctica";
      continents[4] = "North America";
      continents[5] = "South America";
      continents[6] = "Africa";

      对象文字定义对象成员及成员值。对象成员及其值的列表包含在大括号 ({}) 内,成员之间以逗号分隔。在每个成员内,名称和值以冒号 (:) 分隔。以下示例创建了一个对象,并使用名为 AddressCityPostalCode 的三个成员来进行初始化,这些成员的值分别为“123 Anywhere St.”、“Springfield”和“99999”。

      var mailingAddress = { 
           "Address"    :   "123 Anywhere St.", 
           "City"       :   "Springfield", 
           "PostalCode" :   99999
      };
      alert("The package will be shipped to postal code " +
       mailingAddress.PostalCode);

      到目前为止的这些示例说明了如何在数组和对象文字中使用字符串和数值文字。您还可以通过递归使用表示法来表示整个图表,即数组元素和对象成员值本身可以随之使用对象和数组文字。例如,以下代码段说明了一个以数组为成员的对象 (PhoneNumbers),其中该数组由一组对象组成。

      var contact = {
           "Name": "John Doe",
           "PermissionToCall": true,
           "PhoneNumbers": [ 
             {
                 "Location": "Home",
                 "Number": "555-555-1234"
             },
             {
                 "Location": "Work",
                 "Number": "555-555-9999 Ext. 123"
             }
           ]
      };
      if (contact.PermissionToCall)
      {
        alert("Call " + contact.Name + " at " + contact.PhoneNumbers[0].Number);
      }
      注意   在核心 JavaScript 1.5 指南中的文字部分可找到对 JavaScript 文字支持的进一步讨论。

      从 JavaScript 文字到 JSON

      JSON 是依据 JavaScript 中文字对象表示法的子集所创建的数据交换格式。虽然 JavaScript 可接受的文字值语法非常灵活,不过必须注意,JSON 的规则要严格得多。例如,根据 JSON 标准,对象成员的名称必须为有效的 JSON 字符串。JSON 中的字符串必须用引号括起来。而 JavaScript 则允许对象成员以引号或撇号分隔,或者完全省略引号(只要成员名称与保留的 JavaScript 关键字不冲突)。同样,JSON 中的数组元素或对象成员值仅限于一个非常有限的集合。然而,在 JavaScript 中,数组元素和对象成员值几乎可以指一切有效的 JavaScript 表达式,包括函数调用和定义!

      JSON 的优点在于它的简单性。根据 JSON 标准设置格式的消息由单个顶层对象或数组组成。数组元素和对象值可以是对象、数组、字符串、数字、布尔值(true 和 false)或 null。简言之,这就是 JSON 标准!就是如此简单。有关该标准更正式的说明,请参见 www.json.orgRFC 4627

      JSON 的弱点之一是缺少日期/时间文字。许多人首次接触 JSON 后,对此都感到惊讶和失望。缺少日期/时间文字的简单解释(无论能否令人安慰)是 JavaScript 也从未具备此能力:在 JavaScript 中对时间和日期值的支持完全由 Date 对象提供。因此,将 JSON 用作数据格式的大多数应用程序通常会使用字符串或数字来表示日期和时间值。如果使用的是字符串,您通常希望它是 ISO 8601 格式。如果使用的是数字,该值通常表示从 epoch 开始、以通用协调时间 (UTC) 表示的毫秒数,其中 epoch 定义为 1970 年 1 月 1 日午夜 (UTC)。同样,这仅仅是个惯例,而不是 JSON 标准的一部分。如果您要与其他应用程序交换数据,则需要检查其文档,查看它对 JSON 文字内的日期和时间值是如何进行编码的。例如,Microsoft 的 ASP.NET AJAX 使用的就不是上述任一种惯例。它代之以将 .NET DateTime 值编码为 JSON 字符串,字符串内容是 \/Date(ticks)\/,其中 ticks 表示从 epoch (UTC) 开始的毫秒数。因此,UTC 时间 1989 年 11 月 29 日 4:55:30 AM 将编码为“\/Date(628318530718)\/”。

      ASP.NET AJAX:在 JSON 日期和时间字符串内

      ASP.NEXT 中的 AJAX JSON 序列化程序将 DateTime 实例编码为 JSON 字符串。在预发布周期中,ASP.NET AJAX 使用格式“@ticks@”,其中 ticks 表示从通用协调时间 (UTC) 1970 年 1 月 1 日起经过的毫秒数。以 UTC 表示的日期和时间(如 1989 年 11 月 29 日 4:55:30 AM)会编码为“@62831853071@”。虽然简单易懂,但此格式无法区分序列化的日期和时间值与看起来像序列化日期但又不需要进行反序列化的值。因此,ASP.NET AJAX 团队对最终版本进行了更改,通过采用“\/Date(ticks)\/”格式解决了这一问题。

      新格式借助一个小技巧减少了误解的可能性。在 JSON 中,字符串中的正斜杠 (/) 字符可以用反斜杠 (\) 进行转义(即使没有对此进行严格要求)。ASP.NET AJAX 团队利用这点修改了 JavaScriptSerializer,将 DateTime 实例编写为字符串“\/Date(ticks)\/”。两个正斜杠的转义只是表面的,但对 JavaScriptSerializer 至关重要。按照 JSON 规则,\/Date(ticks)\/ 在技术上相当于 /Date(ticks)/,但 JavaScriptSerializer 会将前者反序列化为 DateTime,将后者反序列化为 String。因此与预发布版本的“@ticks@”格式相比,混淆的可能性会大大减少。

      比较 JSON 与 XML

      JSON 和 XML 均能够以基于文本、便于读者阅读的数据交换格式来表示本机内存中对象。此外,两种数据交换格式是同构的,只要文本是一种格式,即可得出另外一种格式的等效文本。例如,调用 可公开访问的 Yahoo! web 服务之一时,您可以通过 querystring 参数指明响应需要设置为 XML 还是 JSON 格式。因此,决定数据交换格式时,不是简单的选此或彼作为银弹的问题,而是要看哪种格式具有成为特定应用程序的最佳选择的“特征”。例如,XML 起源于标记文档文本,而且有继续在该领域发扬光大的趋势(XHTML 就是很好的证明)。而 JSON 则起源于编程语言类型和结构,因此提供了更加自然和便于使用的交换结构化数据映射。除了这两个起点之外,下表可帮助您了解和比较 XML 与 JSON 的重要特征。

      XML 与 JSON 之间的重要特征区别

      特征 XML JSON
      数据类型 不提供任何数据类型概念。必须依靠 XML 架构来添加类型信息。 提供标量数据类型,并能够通过数组和对象表示结构化数据。
      数组支持 必须按照惯例表示数组,例如通过使用外部占位符元素,将数组内容模型化为内部元素。通常,外部元素使用内部元素所用名称的复数形式。 本机数组支持
      对象支持 必须按照惯例表示对象,通常通过混合使用属性和元素。 本机对象支持
      null 支持 需要对 XML 实例文档中的元素使用 xsi:nil,加上导入对应的命名空间。 在本机识别 null 值。
      注释 本机支持,通常通过 API 来提供。 不支持。
      命名空间 支持命名空间,消除了组合文档时的名称冲突风险。命名空间还允许对现有基于 XML 的标准进行安全地扩展。 无命名空间概念。通常通过嵌套对象或在对象成员名称中使用前缀(实际操作中以前者优先),来避免命名冲突。
      格式设置决定 复杂。需要更多精力来决定如何将应用程序类型映射到 XML 元素和属性。会引起热烈争论,讨论以元素为中心还是以属性为中心的方法更好。 简单。为应用程序数据提供更直接的映射。唯一例外是缺少日期/时间文字。
      大小 文档有些冗长,尤其在使用以元素为中心的方法来设置格式时。 语法非常简洁,产生的格式化文本中的大部分空间(理所当然)由所代表的数据使用。
      在 JavaScript 中分析 需要 XML DOM 实现和其他应用程序代码,将文本映射回 JavaScript 对象。 不需要其他应用程序代码便能够分析文本,可以使用 JavaScript 的 eval 函数。
      学习曲线 通常需要同时使用多种技术:XPath、XML 架构、XSLTXML 命名空间DOM 等。 非常简单的技术层次,为具有 JavaScript 或其他动态编程语言背景的开发人员所熟悉。

      JSON 是相对较新的数据交换格式,尚不具备 XML 目前所拥有的多年使用经历和供应商支持(虽然 JSON 正在快速赶超)。下表重点说明了 XML 和 JSON 领域中一些事件的当前状态。

      XML 与 JSON 之间的支持区别

      支持 XML JSON
      工具 具备由众多业界供应商广泛提供的一组成熟工具。 尚不具备丰富的工具支持,如编辑器和格式化程序。
      Microsoft .NET Framework .NET Framework 1.0 之后的版本具有非常优秀和成熟的支持。XML 支持作为基类库 (BCL) 的一部分来提供。对于非托管环境,MSXML 可发挥用武之地。 目前尚无此功能,作为 ASP.NET AJAX 一部分的最初实现除外。
      平台和语言 以众多平台和语言(商业和开源实现)提供了各种广泛使用的分析器和格式化程序。 在众多平台上以多种语言提供了分析程序和格式化程序。有关完整的参考资料,请查询 json.org。目前的大多数实现都可能是开源项目。
      集成语言 业界供应商当前正在试验语言内的“字面”支持。有关详细信息,请参见 Microsoft 的 LINQ 项目 仅在 JavaScript/ECMAScript 中提供本机支持。
      注意 上表均不是比较点的完整列表。其实还可以从更多角度比较两种数据格式,但我们认为这些关键点足以构成一个初步印象。

      使用 JavaScript 创建和分析 JSON 消息

      将 JSON 用作数据交换格式时的两个常见任务是,将本机内存中的表示转换为其 JSON 文本表示,反之亦然。遗憾的是,在撰写文本时,JavaScript 不提供可从给定对象或数组创建 JSON 文本的内置函数。这些方法预计将包含在 2007 年第四版的 ECMAScript 标准中。在 JSON 格式化函数正式添加到 JavaScript 并广泛用于常见实现之前,请使用可从 http://www.json.org/json.js 下载的参考实现脚本。

      在撰写本文时的最新更新中,www.json.org 上的 json.js 脚本将 toJSONString() 函数添加到数组、字符串、布尔值、对象和其他 JavaScript 类型。该标量类型(如数字和布尔值)的 toJSONString() 函数相当简单,因为它们只需返回实例值的字符串表示形式。例如,如果值为 true,Boolean类型的 toJSONString() 函数返回字符串“true”,否则返回“false”。数组和对象类型的 toJSONString() 函数则更有意思。对于 Array 实例,会依次调用每个所包含元素的 toJSONString() 函数,结果会以逗号进行连接从而分隔每个结果。最终输出会包括在方括号内。同样,对于 Object 实例,会枚举每个成员,并调用其 toJSONString() 函数。成员名称及其值的 JSON 表示形式在中间用冒号连接;每个成员名称和值对以逗号分隔,整个输出会包括在大括号内。

      toJSONString() 函数的实际结果是,使用单个函数调用可将所有类型转换为其 JSON 格式。以下 JavaScript 使用详细和非文字方法(用于说明目的),创建了一个 Array 对象并特意添加了七个 String 元素。然后接着显示数组 JSON 表示形式:

      // josn.js must be included prior to this point
      
      var continents = new Array();
      continents.push("Europe");
      continents.push("Asia");
      continents.push("Australia");
      continents.push("Antarctica");
      continents.push("North America");
      continents.push("South America");
      continents.push("Africa");
      
      alert("The JSON representation of the continents array is: " +
       continents.toJSONString());

      图 1. toJSONString() 函数生成根据 JSON 标准设置格式的数组。

      分析 JSON 文本甚至更加简单。由于 JSON 只是 JavaScript 文字的子集,因此可以使用将源 JSON 文本视为 JavaScript 源代码的 eval(expr) 函数来分析内存中表示形式。eval 函数接受输入有效 JavaScript 代码的字符串,并计算表达式结果。因此,下面一行代码是将 JSON 文本转换为本机表示形式所需的全部代码:

      var value = eval( "(" + jsonText + ")" );
      注意 使用额外的圆括号可使 eval 将来源输入无条件地视为表达式。这对于对象来说尤其重要。如果您尝试使用包含 JSON 文本的字符串调用 eval,其中该文本定义了对象,如字符串“{}”(表示空对象),那么它只会返回未定义作为分析结果。圆括号会强制 JavaScript 分析器将顶层大括号视为 Object 实例的文字表示法,而不是定义语句块的大括号。同样,如果顶层项是一个数组,如 eval("[1,2,3]"),也不会发生同样的问题。然而,出于一致性需要,在调用 eval 之前 JSON 文本应始终用圆括号括起来,以便分析来源时不会产生歧义。

      对文字表示法计算结果后,会返回与文字语法对应的实例,并将其赋值给 value。请看下面的例子:它使用 eval 函数分析数组的文字表示法,并将得到的数组赋值给变量 continents

      var arrayAsJSONText = '["Europe", "Asia", "Australia", "Antarctica",
       "North America", "South America", "Africa"]';
      var continents = eval( arrayAsJSONText );
      alert(continents[0] + " is one of the " + continents.length + "
       continents.");

      当然,实际操作中被计算结果的 JSON 文本会来自一些外部源,而不是像上述情况中被硬编码。

      eval 函数会盲目地对它传递的任一表达式计算结果。不可靠的来源会因此包含具潜在危险的 JavaScript,附带于或混入组成 JSON 数据的文字表示法。在来源不受信任的情况下,强烈建议您使用 parseJSON() 函数(位于 json.js 中)对 JSON 文本进行分析:

      // Requires json.js
      var continents = arrayAsJSONText.parseJSON();

      parseJSON() 函数也使用 eval,但仅限于 arrayAsJSONText 中包含的字符串符合 JSON 文本标准时。它通过一个更智能的正则表达式测试来完成这一操作。

      在 .NET Framework 中使用 JSON

      JSON 文本可依据 JavaScript 代码轻松地进行创建和分析,这是它的一个吸引人之处。但是,当 JSON 用于 ASP.NET web 应用程序时,只有浏览器受 JavaScript 支持,因为服务器端代码很可能是用 Visual Basic 或 C# 编写的。

      大多数为 ASP.NET 设计的 Ajax 库都支持以编程方式创建和分析 JSON 文本。因此,要在 .NET 应用程序中使用 JSON,请考虑使用其中一个库。有众多的开源和第三方方案可供选择,而 Microsoft 也有自己的 Ajax 库,名为 ASP.NET AJAX

      在本文中,我们会介绍使用 Jayrock 的示例,它是一种用于 Microsoft .NET Framework 的 JSON 开源实现,由合著者 Atif Aziz 创建。我们选择使用 Jayrock 而非 ASP.NET AJAX 的原因有三个:

      • Jayrock 是开源的,可以按需要扩展或自定义。
      • Jayrock 可用于 ASP.NET 1.x,、2.0 和 Mono 应用程序,而 ASP.NET AJAX 仅限于 ASP.NET 2.0 版。
      • Jayrock 的作用域仅限于 JSON 和 JSON-RPC,前者是本文的重点内容。ASP.NET AJAX 包括对创建和分析 JSON 文本的一些支持,但它的主要用途是提供一个丰富的平台,在 ASP.NET 中构建端到端 Ajax 风格的 web 应用程序。您的重点内容为 JSON 时,额外的点缀性功能反而会让人分神。

      在 .NET 中通过 Jayrock 使用 JSON,与在 .NET Framework 中通过 XmlWriterXmlReaderXmlSerializer 类使用 XML 相似。位于 Jayrock 中的类 JsonWriterJsonReaderJsonTextWriterJsonTextReader 模拟 .NET Framework 类 XmlWriterXmlReaderXmlTextWriterXmlTextReader 的语义。这些类在低级别和面向流的级别与 JSON 交互时非常有用。使用这些类,可通过一系列的方法调用逐个创建或分析 JSON 文本。例如,使用 JsonWriter 类方法 WriteNumber(number) 可根据 JSON 标准写出适当的“数字”形式的字符串表示形式。JsonConvert 类提供了用于在 .NET 类型和 JSON 之间进行转换的 ExportImport 方法。这些方法提供了分别与 XmlSerializer 类方法 SerializeDeserialize 相似的功能。

      创建 JSON 文本

      以下代码说明了如何使用 JsonTextWriter 类来创建洲字符串数组的 JSON 文本。此 JSON 文本会发送到传入构造函数的 TextWriter 实例,在此示例中正好是来自控制台的输出流(在 ASP.NET 中您可以使用 Response.Output):

      using (JsonTextWriter writer = JsonTextWriter(Console.Out))
      {
          writer.WriteStartArray();
          writer.WriteString("Europe");
          writer.WriteString("Asia");
          writer.WriteString("Australia");
          writer.WriteString("Antarctica");
          writer.WriteString("North America");
          writer.WriteString("South America");
          writer.WriteString("Africa");
          writer.WriteEndArray();
      }

      除了 WriteStartArrayWriteStringWriteEndArray 方法之外,JsonWriter 类还提供了用于编写其他 JSON 值类型的方法,如 WriteNumberWriteBooleanWriteNull 等。WriteStartObjectWriteEndObjectWriteMember 方法为对象创建 JSON 文本。以下示例说明了如何为“了解 JavaScript 中的文字表示法”部分探讨的联系对象创建 JSON 文本:

      private static void WriteContact()
      {
          using (JsonWriter writer = new JsonTextWriter(Console.Out))
          {
              writer.WriteStartObject();              //  {
              writer.WriteMember("Name");             //      "Name" : 
              writer.WriteString("John Doe");         //          "John Doe",
              writer.WriteMember("PermissionToCall"); //      "PermissionToCall"
       :
              writer.WriteBoolean(true);              //          true,
              writer.WriteMember("PhoneNumbers");     //      "PhoneNumbers" :
              writer.WriteStartArray();               //          [ 
              WritePhoneNumber(writer,                //            {
       "Location": "Home",
                  "Home", "555-555-1234");            //              "Number":
       "555-555-1234" },
              WritePhoneNumber(writer,                //            {
       "Location": "Work",
                  "Work", "555-555-9999 Ext. 123");   //              "Number":
       "555-555-9999 Ext. 123" }
              writer.WriteEndArray();                 //          ]
              writer.WriteEndObject();                //  }
          }
      }
      
      private static void WritePhoneNumber(JsonWriter writer, string location,
       string number)
      {
          writer.WriteStartObject();      //  {
          writer.WriteMember("Location"); //      "Location" : 
          writer.WriteString(location);   //          "...", 
          writer.WriteMember("Number");   //      "Number" :
          writer.WriteString(number);     //          "..."
          writer.WriteEndObject();        //  }
      }

      JsonConvert 类中的 ExportExportToString 方法可用于将指定的 .NET 类型序列化为 JSON 文本。例如,不需要使用 JsonTextWriter 类为七大洲数组手动构建 JSON 文本,以下对 JsonConvert.ExportToString 的调用即可产生相同的结果:

      string[] continents = {
            "Europe", "Asia", "Australia", "Antarctica", "North America", "South
       America", "Africa"
      };
      string jsonText = JsonConvert.ExportToString(continents);

      分析 JSON 文本

      JsonTextReader 类提供了各种分析 JSON 文本令牌的方法,其中核心的一种是 Read。每次调用 Read 方法时,分析器会使用下一个令牌,可能是字符串值、数字值、对象成员名称、数组开头等。可能的话,可以通过 Text 属性访问当前令牌的已分析文本。例如,如果该读取器位于 Boolean 数据中,则 Text 属性会根据实际分析值返回“true”或“false”。

      以下示例代码使用 JsonTextReader 类,对包含七大洲名称的字符串数组的 JSON 文本表示形式进行分析。每个以字母“A”开头的洲会发送到控制台:

      string jsonText = @"["Europe", "Asia", "Australia", "Antarctica",
       "North America", "South America", "Africa"]";
      
      using (JsonTextReader reader = new JsonTextReader(new
       StringReader(jsonText)))
      {
          while (reader.Read())
          {
              if (reader.TokenClass == JsonTokenClass.String &
                  reader.Text.StartsWith("A"))
              {
                  Console.WriteLine(reader.Text);
              }
          }
      }
      注意Jayrock 中的 JsonTextReader 类是一个非常自由的 JSON 文本分析器。它实际上允许的语法要比 RFC 4627 中列出的规则所规定的有效 JSON 文本多得多。例如,就象在 JavaScript 中一样,JsonTextReader 类允许单行和多行注释出现在 JSON 文本内。单行注释以双斜杠 (//) 开头,多行注释以斜杠星号 (/*) 开头,并以星号斜杠 (*/) 结尾。单行注释甚至能以井字号 (#) 开头,这在 Unix 样式的配置文件中十分常见。在所有实例中,分析器会完全跳过注释,不会通过 API 公开。和在 JavaScript 中一样,JsonTextReader 允许以撇号 (') 分隔 JSON 字符串。该分析器甚至可以容忍最后一个对象成员或者数组元素后面多余的逗号。
      即使具备所有这些附加内容,JsonTextReader 仍是符合标准的分析器!而 JsonTextWriter 则只能产生严格符合标准的 JSON 文本。这遵循了通常所说的可靠性原则,即“严以律己,宽以待人”。

      要将 JSON 文本直接转换为 .NET 对象,请使用 JsonConvert 类导入方法,指定输出类型和 JSON 文本。以下示例显示了从 JSON 字符串数组到 .NET 字符串数组的转换:

      string jsonText = @"["Europe", "Asia", "Australia", "Antarctica",
       "North America", "South America", "Africa"]";
      
      string[] continents = (string[]) JsonConvert.Import(typeof(string[]),
       jsonText);

      以下是一个更有意思的转换示例:取得 RSS XML 源,使用 XmlSerializer 将其反序列化为 .NET 类型,然后使用 JsonConvert 将该对象转换为 JSON 文本(将 XML 格式的 RSS 有效转换为 JSON 文本):

      XmlSerializer serializer = new XmlSerializer(typeof(RichSiteSummary));
      RichSiteSummary news;
      
      // Get the MSDN RSS feed and deserialize it...
      
      using (XmlReader reader = XmlReader.Create("http://msdn.microsoft.com/rss.xml"))
      {
          news = (RichSiteSummary) serializer.Deserialize(reader);
      }
      
      
      // Export the RichSiteSummary object as JSON text, emitting the output to
       Console.Out
      
      using (JsonTextWriter writer = new JsonTextWriter(Console.Out))
      {
          JsonConvert.Export(news, writer);
      }
      注意 可在本文附带的示例中找到 RichSiteSummary 定义及其相关类型。

      在 ASP.NET 中使用 JSON

      我们已经介绍了如何在 JavaScript 中、以及通过 Jayrock 在 .NET Framework 中使用 JSON,接下来我们来看一个关于在何处以及如何应用这些知识的实际示例。考虑 ASP.NET 2.0 的客户端脚本回调功能,它可简化 web 浏览器向 ASP.NET 页面(或向页面中的特定控件)发出带外调用的过程。在典型的回调情形中,浏览器中的客户端脚本将数据打包并回送到 web 服务器,由服务器端方法进行某些处理。从服务器收到响应数据后,客户端会用它来更新浏览器显示。

      注意 可在《MSDN 杂志》的文章“ASP.NET 2.0 中的脚本回调”中找到更多信息。

      客户端回调情形中的难题在于,客户端和服务器只能来回运送一个字符串。因此,待交换的信息必须在发送前从本机内存中的表示形式转换为字符串,然后在收到后从字符串分析回本机内存中的表示形式。ASP.NET 2.0 中的客户端脚本回调功能不要求进行交换的数据使用特定字符串格式,也不提供在本机内存中和字符串表示之间进行转换的任何内置功能;开发人员可以依据所选择的数据交换格式来实现转换逻辑。

      以下示例说明了如何在客户端脚本回调情形中将 JSON 用作数据交换格式。特别是,该示例由 ASP.NET 页面组成,此页面使用 Northwind 数据库中的数据,以下拉列表形式提供类别列表;选定类别中的产品则显示在项目符号列表中(请参见图 3)。每当客户端更改下拉列表时,将发生回调并传入唯一元素为选定 CategoryID 的数组。

      注意 我们传入的是包含选定 CategoryID 作为其唯一元素的数组(而不仅仅是 CategoryID),因为 JSON 标准要求任何 JSON 文本都必须有对象或数组作为其根。当然,客户端不需要向服务器传递 JSON 文本,在此示例中本来可以只将选定的 CategoryID 作为字符串进行传递。但是,我们想要演示在回调的请求和响应消息中发送 JSON 文本。

      Page_Load 事件处理程序的以下代码配置了 Categories DropDownList Web 控件,以便在它发生更改时调用 GetProductsForCategory 函数,并传递选定的下拉列表值。如果传入的下拉列表值大于零,此函数会初始化客户端脚本回调:

      // Add client-side onchange event to drop-down list
      Categories.Attributes["onchange"] = "Categories_onchange(this);";
      
      // Generate the callback script
      string callbackScript = ClientScript.GetCallbackEventReference(
          /* control        */ this, 
          /* argument       */ "'[' + categoryID + ']'", 
          /* clientCallback */ "showProducts", 
          /* context        */ "null");
      
      // Add the Categories_onchange function
      ClientScript.RegisterClientScriptBlock(GetType(),
      "Categories_onchange", @"
          function Categories_onchange(sender)
          {
              clearResults();
      
              var categoryID = sender.value;            
              if (categoryID > 0)
              {
                  " + callbackScript + @"
              }
          }", true);

      ClientScriptManager 类中的 GetCallBackEventReference 方法用于生成可调用回调的 JavaScript 代码,具有以下签名:

      public string GetCallbackEventReference (
          Control control,
          string argument,
          string clientCallback,
          string context,
      )

      argument 参数指定回调期间哪些数据会从客户端发送到 web 服务器,clientCallback 参数则指定在回调完成时调用的客户端函数的名称 (showProducts)。GetCallBackEventReference 方法调用会生成以下 JavaScript 代码,并将它添加到呈现的标记中:

      WebForm_DoCallback('__Page','[' + categoryID + 
      ']',showProducts,null,null,false)

      '[' + categoryID + ']' 是回调期间传递到服务器的值(具有单个元素 categoryID 的数组),showProducts 则是回调返回时执行的 JavaScript 函数。

      在服务器端,响应回调而执行的方法使用 Jayrock 的 JsonConvert 类来分析传入的 JSON 文本,并设置传出 JSON 文本的格式。特别值得注意的是,与选定类别相关的产品的名称都作为一个字符串数组进行检索并返回。

      // Deserialize the JSON text into an array of integers
      int[] args = (int[]) JsonConvert.Import(typeof(int[]), eventArgument);
      
      // Read the selected CategoryID from the array
      int categoryID = args[0];
      
      // Get products based on categoryID 
      NorthwindDataSet.ProductsRow[] rows = Northwind.Categories.FindByCategoryID(categoryID).GetProductsRows();
      
      // Load the names into a string array
      string[] productNames = new string[rows.Length];
      for (int i = 0; i < rows.Length; i++)
      {
          productNames[i] = rows[i].ProductName;
      }// Serialize the string array as JSON text and return it to the clientreturn JsonConvert.ExportToString(productNames);
      注意JsonConvert 类使用了两次——第一次是将 eventArgument 中的 JSON 文本转换为整数数组,第二次是将该字符串数组 productNames 转换为 JSON 文本,以返回到客户端。或者,我们也可以使用此处的 JsonReaderJsonWriter 类,但在涉及数据相对较小并易于映射到现有类型的情况下,JsonConvert 可以将同样的工作做得相当好。

      数据从服务器端返回时,会调用依据 GetCallBackEventReference 方法指定的 JavaScript 函数,并传递返回值。此 JavaScript 方法 showProducts 以引用 <div> 元素 ProductOutput 开始。然后它会分析 JSON 响应,并动态添加无序列表,每个数组元素一个列表项。如果没有返回选定类别的产品,则会显示相应的消息。

      function showProducts(arg, context)
      {
          // Dump the JSON text response from the server.
      
          document.forms[0].JSONResponse.value = arg;
          
          // Parse JSON text returned from callback.
      
          var categoryProducts = eval("(" + arg + ")");
      
          // Get a reference to the <div> ProductOutput.
          
          var output = document.getElementById("ProductOutput");
      
          // If no products for category, show message.
          
          if (categoryProducts.length == 0)
          {
              output.appendChild(document.createTextNode("There are no products
       for this category..."));
          }
          else
          {
              // There are products, display them in an unordered list. 
              
              var ul = document.createElement("ul");
              
              for (var i = 0; i < categoryProducts.length; i++)
              {
                  var product = categoryProducts[i];
                  var li = document.createElement("li");
                  li.appendChild(document.createTextNode(product));
                  ul.appendChild(li);
              }
              
              output.appendChild(ul);
          }
      }

      图 2 说明了事件顺序,图 3 显示了此示例的运作过程;完整的代码包括在本文下载中。

      图 2:客户端将选定的 CategoryID 作为数组中的单个元素进行发送,服务器则返回相关产品名称的数组。

      图 3:产品显示在选定类别内的项目符号列表中。

      结束语

      JSON 是一种基于文本的轻型数据交换格式,以 JavaScript 编程语言中文字表示法的子集为基础。它提供了用于应用程序数据结构的简洁编码,通常用于一种或两种应用程序交换数据都可以使用 JavaScript 实现的情况,如 Ajax 风格的 web 应用程序。JSON 的吸引人之处在于简单易懂、便于采用和实现。JSON 对于已经熟悉 JavaScript 或同样支持丰富文字表示法的其他编程语言(如 Python 和 Ruby)的开发人员来说,实际上没有学习曲线。只需调用 eval 函数,即可完成对 JavaScript 代码中 JSON 文本的分析;使用 http://www.json.org/json.js 上提供的 json.js 脚本,即可轻松创建 JSON 文本。

      有许许多多的库可帮助在所有主要的平台和框架中使用 JSON。本文中我们介绍了 Jayrock,它是用于在 .NET 应用程序中创建和分析 JSON 文本的开源库。Jayrock 可用于 ASP.NET 1.x、2.0 和 Mono 应用程序。ASP.NET AJAX 提供相似的 JSON 功能,但仅限于 ASP.NET 2.0 应用程序。

      快乐编程!

      Ajax 还是 AJAX?

      Ajax 这个术语最初由 Jesse James Garrett 设想出来,用于描述 web 应用程序风格和创建高度交互的 web 应用程序所需的一组技术。从前,术语 Ajax 作为 Asynchronous JavaScript And XML(异步 JavaScript 和 XML)的缩写 AJAX 在 web 上传播。但随着时间的变化,人们意识到 AJAX 中的“X”无法形象地代表与后台 web 服务器进行通信时使用的基础数据格式,因为大多数实现都转向 JSON 作为更简单而有效的替代方案。因此,没有人提出如 AJAJ(有些拗口)之类的替代缩写,该缩写基本上已引退,而倾向于采用“Ajax 术语”而非“AJAX 缩写”。

      在撰写本文时,希望看到混合及广泛使用的“AJAX”和“Ajax”具有同一含义。在本文中,我们坚持“Ajax 术语”。但是,如果商业产品要提供启用 Ajax 样式应用程序的框架,则需要使用缩写形式来区分与其名称类似的洗涤剂产品,避免可能的商标或法律争端。

      参考资料

      特别感谢

      在本文提交给 MSDN 之前,有许多人自愿帮助我们校对文章,并对内容、语法和方向等方面提出了宝贵意见。审校过程的主要参与者有 Douglas Crockford、Eric Schönholzer 和 Milan Negovan。

      作者简介

      Atif Aziz 是 Skybow AG 的首席顾问,他的主要职责是帮助客户了解和构建 .NET 开发平台上的解决方案。Atif 通过会议演讲以及为技术出版物撰写文章,经常为微软开发人员社区出力。他是一位 INETA 发言人,并且是瑞士最大的 .NET 用户组的总裁。您可以通过他的网站 http://www.raboof.com/ 与他联系。

      Scott Mitchell 是六部 ASP/ASP.NET 书籍的作者及 4GuysFromRolla.com 网站的创立者。自 1998 年以来,他一直从事 Microsoft web 技术方面的工作。Scott 是一位独立技术顾问、培训专家兼作家。可通过他的博客与其联系:http://ScottOnWriting.net

      posted @ 2008-05-23 12:29 meetrice 阅读(121) 评论(0) 编辑
      什么是架构
      • Rolph Johnson认为:架构是一种主观上的东西,是专家级的项目开发人员对系统设计的一些可共享的理解
      • 架构中包括一些决定,开发者希望这些决定能尽早作出,因为在开发者看来它们是难以改变的。
      •  如果你发现某些决定不像你想象中的那么难以改变,那么它就不再与架构相关
      • 理解: B/S (SmartClient、C/S) 架构, DotNet 架构, J2EE架构

      企业应用的特点

      1. 涉及到持久化数据
      2. 很多人同时访问数据
      3. 含有大量操作数据的用户界面
      4. 与散布在企业内部或周围的其他的应用集成
      5. 各种异构系统的概念含有不一致性
      6. 业务逻辑通常是最没有逻辑的东西
      7. 企业应用并非都是大型的,但可能都为企业提供巨大的价值

        · 性能:多时候,增加更多的服务器比增加更多的程序员便宜;如果增加服务器对性能的提升较大,则说明应用的伸缩性好 

      · 分层:上层是用下层定义的各种服务,而下层对上层一无所知;分层的缺陷是不能封装所有的东西,因此可能带来级联更改,过多的曾影响性能;LayerTier的区别是Tier可能更多的意味物理上的分离      

      Brown分层模型

      表现层>>控制层>>领域层>>数据映射层>>数据源层  

      Core J2EE分层模型

      客户层>>表现层>>业务层>>集成层>>资源层 

      MS DNA分层模型

      表现层>>业务逻辑层>>数据访问层 

      Marinescu分层模型

      表现层>>应用层>>服务层>>领域层>>持久层


      · 领域模型:使用不同职责的对象来联合解决业务问题,而不是通过事务脚本来处理数据 

      · 阻抗不匹配:对象模型和关系型数据库之间的不匹配,通常通过对象-关系映射(ORM)解决 

      · 软件事务的四个特性 

      1.      原子性:要么全部成功,要么全部会滚

      2.      一致性:事务开始和完成时,资源都不应该被破坏

      3.      隔离性:事务成功完成之前,其影响不应该被看到

      4.      持久性:事务不会因为任何崩溃而丢失更改 

      · 事务的隔离级别(由高而低)

      1.      可串行化:完全隔离,并发执行的结果与以某种顺序依次执行的结果相同

      2.      可重复读:允许幻读,更新者向集合中插入了一些元素而读的人只能看到其中一部分

      3.      读已提交:允许不可重复读,所有已经提交的数据都可以读

      4.      读未提交:允许脏读,允许读未提交的数据 

      · 会话状态:无状态对象是一种不良设计;用无状态的服务器可以实现有状态的会话;如果有很多会话空闲,可以考虑用数据库存储会话;如果需要频繁访问会话,则应该使用服务器会话 

      · 分布策略:分布对象的第一定律:不要使用分布对象;分布对象的第二定律:节约使用分布对象

      领域逻辑模式分为 事物脚本、领域模型、表模块和服务层四种模式

        很多设计者喜欢把业务逻辑分成两类:领域逻辑和应用逻辑,前者只与问题领域有关、而后者有时被称为工作流逻辑

      1. 事物脚本

        通过使用SQL语句或者存储过程返回记录集,记录集在系统的各层之间传递,在必要的时候可以通过更新记录集、使用SQL语句或者存储过程的方式更新数据库
        事物脚本胜在简单,通常应用在小型的项目和系统中,但业务逻辑越来越复杂,使用这一模式就越来越难以保持良好设计,因为在程序里面充斥了大量的SQL语句和命令,一旦数据结构发生更改或者需要对系统进行修改,可能会出现许多难以发现的问题

      2. 领域模型

        领域模型是合并了行为和数据的领域的对象模型,领域模型创建了一张由互联对象组成的网,其中的每个对象都代表着某个有意义的个体,可能大到一个公司或者小到订单的一行

        简单领域可以使用活动记录,即简单的单条数据记录和单个对象对应的模式,一个对象对应数据库中的一个表

        复杂领域模型需要使用数据映射器,它可能使用继承、策略或者其他的设计模式,是一张由互联的细粒度对象组成的复杂网络,我们经常会看到:多个类通过交互来完成很简单的任务

        在面向对象技术中,通过从一个对象到另一个对象的连续传递可以把行为传递给最有资格处理的对象,它同时消除了很多条件判断行为

      领域模型的要点在于隐藏数据库的存在

      3. 表模块

        表模块是处理某一数据库表或视图中所有行的业务逻辑的一个实例

        表模块通过强类型或弱类型的数据集与对象结合使用,使用主键查询数据,是.Net中使用的很多的一种模式,主要使用主键、半对象化的操作数据---之所以说是半结构化,是因为所用的对象基本上只具有行为,通过传入参数执行特定的操作或者查询记录集,而几乎不承载任何数据

        在.net中,这种模式因为其容易和UI进行绑定和交互,所以倍受欢迎


      4. 服务层

        通过一个服务层来定义应用程序边界,在服务层中建立一组可用的操作的集合,并在每个操作内部协调应用程序的响应

        服务层是一种组织业务逻辑的模式,有点类似于业务外观;WEB SERVICE通常担任着服务层的角色

        服务层可以通过领域外观方法和操作脚本方法实现,领域外观方法中,服务层以领域模型之上的瘦外观集合方式出现,负责实现外观的类中不不包含业务逻辑;而在操作脚本方法中 ,服务层由一组相对复杂的类组成,这些类直接实现应用逻辑,但将领域逻辑委托给封装好的领域对象类

         服务层的类的接口是粗粒度的,适合于远程调用。但是,在开始时,我们应该仅设计一个本地调用的服务层,在需要远程调用时,再在服务层上增加一个远程外观。


      并发管理的正确目标是尽量增加对数据的正确访问,同时减少冲突
        离线并发模式有两种:使用乐观离线锁、使用悲观离线锁

        离线锁可以理解为一种非服务器管理的锁,或者说是自管理的锁,应用在适当的地方注册锁,获取数据,然后离线,并对数据进行离线的操作;其他的应用通过检测已经注册的锁来决定是否进行并发操作

      1. 悲观离线锁


         悲观离线锁假设会话冲突的可能性很大,从而对系统的并发进性进行限制
         在对不一致读的要求不高时,第一选择是使用独占写锁(不可以再添加任何读锁,当然写锁也不能);如必须读出最新数据,而不在乎是否要修改,则应使用独占读锁(不可以再添加任何写锁,但读锁是允许的)。结合以上两种,提供互斥读锁的限制,又有互斥写锁的并发性的锁称为 读/写锁---读/写锁互斥不能同时加,但并发的读锁是允许的
         构建悲观离线锁的步骤:决定使用哪种锁>>构建一个锁管理对象>>定义业务事务使用锁的过程
         让锁管理对象在锁不可用时抛出异常而不是等待锁释放,可以免除死锁
         悲观离线锁作为乐观离线锁的补充,只在真正需要的时候才应该使用 


      2. 乐观离线锁

         乐观离线锁假设会话冲突的可能性很小,从而使得多用户对一份数据进行处理成为可能
        通过冲突检测和事务会滚来防止并发事务中的冲突
        本质就是通过将会话中的版本号与当前记录数据的版本号相比较,事务成功提交以后版本号增加;或者在更新的SQL语句中包含对所有字段的检查,可以不需要为数据库增加版本字段,但可能导致性能损失
        乐观离线锁必须自定检查以防止不一致读
        一个高效的合并策略能使乐观离线锁变得非常强大,当冲突发生时,合并策略可以合并更改并重新提交

      posted @ 2008-05-23 12:19 meetrice 阅读(92) 评论(0) 编辑
      posted @ 2008-05-23 09:17 meetrice 阅读(1315) 评论(0) 编辑

      1) 表格数据选择


      行选择模式:

      Js代码 复制代码
      1. var rowcount = grid.getSelectionNode().getSelections();  


      可以获取全部选中的记录,得到的rowcount将是一个Array,比如想获取sex列的数据,语句如下

      Js代码 复制代码
      1. var strsex = rowcount[i].get(‘sex’);  


      单元格选择模式


      如果在GridPanel的配置属性增加sm属性如下

      Js代码 复制代码
      1. sm:new Ext.grid.CellSelectionModel();  

       则表格的选择模式为单元格选择模式。当单击时将选中对应的某一个单元格,而不是默认的选择某一行。选择方式如下

      Js代码 复制代码
      1. var cell = grid.getSelectionNode().getSelectedCell();  


      得到的cell记录了当前选择的行(cell[0])以及列(cell[1]).可以通过一下语句得到该单元格数据

      Js代码 复制代码
      1. var colname = grid.getColumnModel().getDataIndex(cell[1]);  //获取列名   
      2. var celldata = grid.getStore().getAt(cell[0]).get(colname); //获取数据  


      getStore():获取表格的数据集
      getAt():获取该数据集cell[0]行
      get():获取该行colname的数据


      2) 为表格增加链接


      有时我们需要为表格中的某一列添加一个链接。可以利用renderer配置属性为该列添加html
      如下:{id:'3',header:'名称',dataIndex:'name',renderer:DomUrl},
      定义DomUrl方法

       

      Js代码 复制代码
      1. function DomUrl(value){   
      2. return "<a href=>"+value+"</a>";   
      3. }  


      如果表格内的数据是一个链接如:www.sina.com这样写法自然没有问题,但是大多数时候我们在表格中不会直接写一个链接,如果又需要根据单元格内容动态为链接添加几个参数。那这种写法就几乎没有什么用了。因为这个属性是在表格初始化的时候定义好的,而且表格初始化之后这个属性无法改变,也就是只读属性。


      处理方法如下:
      定义一个全局变量,初始值为0;DomUrl函数如下

      Js代码 复制代码
      1. function DomUrl(value){   
      2. var row = grid.getSelectionModel().selectRow(startrow);//选中当前行   
      3. var rownum = grid.getSelectionModel().getSelected();//获取当前行   
      4. startrow ++;   
      5. var strurl = "abc.jsp?id=" + rownum.get('id');//获取当前选中行的值,并组织链接字符串   
      6. return "<a href='"+strurl+"'>"+value+"</a>";   
      7. }  


      不过不要忘记在下次提交的时候将startrow赋值为0。


      3) 表格的属性


              表格的属性分为配置属性(在操作表格时无法修改),以及其他可读写属性,方法,以及事件。如下:


       配置属性


      a) activeItem:渲染布局时激活的子元素。
      b) applyTo:指定渲染对象。
      c) autoDestroy:当容器的子元素从容器中移除时是否自动销毁。
      d) autoExpandColumn:指定自动填充表格剩余区域的列id
      e) autoExpandMax:可自动扩张的最大宽度。
      f) autoExpandMin:可自动扩张的最小宽度
      g) autoHeight:自动扩充高度
      h) autoShow:是否自动显示
      i) autoWidth:自动扩充宽度
      j) bbar/tbar:底部/顶部状态栏
      k) bufferResize:容器再布局的缓冲频率
      l) colModel/cm:列模式
      m) cls:组件的额外css格式。
      n) collapsible:是否显示快捷隐藏按钮
      o) defaults:指定默认配置。
      p) disableSelection:是否禁止选择表格行或列
      q) enableDragDrop:是否允许表格列的拖放操作。
      r) enableHdMenu:是否显示表格列的菜单。
      s) frame:边框是否显示
      t) loadMask: 是否显示加载动画
      u) selModel/sm:表格选择模式
      v) store:表格数据集
      w) stripeRows:是否显示分隔线。
      x) title:表格标题


      方法


      a) getColumnModel():得到表格列模型
      b) getGridEl():得到表格下的元素
      c) getPosition():得到组件的当前位置,返回一个数组
      d) getSelectionModel():得到选中模型
      e) getSize():得到组件大小
      f) getStore():得到组件的数据集
      g) getView():得到表格的GridView对象。
      h) hide():隐藏当前组件
      i) isVisible():判断当前组件是否显示
      j) setDisabled( Boolean):设置组件的可用性
      k) un():解除组件的监听
      l) on():为组件添加监听
      on ( String eventName, Function handler, [Object scope] )
      eventName:添加监听的名称
      handler:事件处理函数
      scope:事件响应的作用域,包括scope,delay,single,buffer。
        

      posted @ 2008-05-23 09:15 meetrice 阅读(1078) 评论(0) 编辑

      说明: 本教程在我推荐的ajax/ext目录规范环境下开发,如环境不同,请自行修改相关路径

      本项目框架及代码在此下载


      1.打开项目

      01.jpg


      2.在根目录下建立demo.html:

       

      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=GBK">
      <title>ExtJs Gui Designer Demo</title>
      <!-- The ExtJs base 2.02 -->
      <link rel="stylesheet" type="text/css" href="framework/ext-2.0.2/resources/css/ext-all.css" temp_href="framework/ext-2.0.2/resources/css/ext-all.css"/>
      <script type="text/javascript" src="framework/ext-2.0.2/adapter/ext/ext-base.js" temp_src="framework/ext-2.0.2/adapter/ext/ext-base.js"></script>
      <script type="text/javascript" src="framework/ext-2.0.2/ext-all.js" temp_src="framework/ext-2.0.2/ext-all.js"></script>

      <!-- The Json Panel -->
      <script type="text/javascript" src="widget/Ext.ux.JsonPanel.js" temp_src="widget/Ext.ux.JsonPanel.js"></script>
      </head>

      <body>
      <script>
      new Ext.Viewport({
      items : 
      new Ext.ux.JsonPanel({autoLoad:'modules/user.json'}),
      layout: 
      'fit'
      }
      ).show();
      </script>
      </body>
      </html>

      注意 其中user.json就是GUIBUILDER中生成的代码.

      3.打开GuiBuilder


      02.jpg


      4.设计界面

      1).首先双击 FormPanel,或把FormPanel拖进主面板

      03.jpg

      2)接着拖动TextField进入FormPanle,并修改FieldLabel为"用户名",添加"id"属性为"username"

      04.jpg

      3)再插入一个按钮button,添加handle事件

      05.jpg

      4)点击click here to edit,弹出脚本编辑框,在其实输入:


      function(){


      alert(Ext.get("username").getValue());


      }

      输入,点击apply

      06.jpg

      5) 点击 copy json,或打开edit json,拷贝其中的代码,将其另存为user.json

      6) 打开demo.html

      07.jpg

      posted @ 2008-05-23 08:38 meetrice 阅读(2362) 评论(2) 编辑