1、ExtJs学习笔记ExtJs学习笔记目录1. ExtJs 结构树 22. 对ExtJs的态度 33. Ext.form概述 44. Ext.TabPanel篇 55. Function扩展篇 76. Ext.data.Store篇 107. Ext.data.JsonReader篇一 128. Ext.data.JsonReader篇二 159. Ext.data.HttpProxy篇 1910. Ext.data.Connection篇一 2011. Ext.data.Connection篇二 2412. Ext.Updater篇一 2613. Ext.Updater篇二 2714. JSO
2、N序列化篇 3315. 通信篇 3516. extJs 2.0学习笔记(Ajax篇) 3817. extJs 2.0学习笔记(Ext.data序论篇) 3918. extJs 2.0学习笔记(Ext.Panel终结篇) 4019. extJs 2.0学习笔记(事件注册总结篇) 4520. extJs 2.0学习笔记(Ext.Panel篇一) 4821. extJs 2.0学习笔记(Ext.Panel篇二) 5022. extJs 2.0学习笔记(Ext.Panel篇三) 5923. extJs 2.0学习笔记(Ext.Panel篇四) 6224. extJs 2.0学习笔记(组件总论篇) 66
3、25. extJs 2.0学习笔记(Ext.Element API总结) 6926. extJs 2.0学习笔记(Element.js篇) 7327. extJs 2.0学习笔记(DomHelper.js篇) 7628. extJs 2.0学习笔记(ext.js篇) 771. ExtJs 结构树2. 对ExtJs的态度extjs的确是个好东西,但是,它的优点也就是它的缺点: 加载页面慢 时间一长,浏览器占内存就会疯长 服务器端功能极度削弱,除了数据库操作外,几乎所有功能都到了客户端,还得用javascript来写。 功能全到了客户端,而客户端语言javascript的编写还是有许多的麻烦,真正
4、精通它的人极少。 javascript对于大部分人来说,不易调试 大量存在的javascript代码难以维护 开发速度极慢。 extjs本身还存在一些问题正是因为有这么多的问题,老板们都得掂量一下了。用它倒底值不值。当然,这儿也得说一下它的优点: 因为一切都是javascript搞定,所以,界面上的问题再也不像以前一样让人郁闷了,客户端对界面的的操作取得极大的便利,而不像以前一样,服务器端生成n多垃圾代码,以前的时代就彷佛隔靴搔痒,服务器端企图布置好一切。现在不同了,客户端用一个Ext.Ajax.Request请求数据方便,然后,显示出来也容易。 又回到了c/s时代。c/s让人神往啊。web该
5、死的无状态让人郁闷 学习extjs的一个极大的好处,所有当前web开发界面上的需求都可以在这儿找到答案。通过研究它的代码,我们可以开发出自己的ajax框架来,可以写出适合于自己的widgets来。而不用背着extjs那个大乌龟壳。我认为,不宜用extjs来开发整个应用,但是,在极为需要的地方用一用,还是蛮好的,整个站点都用它那就麻烦了。现在我对于选择ajax框架有了一点心得。不要使用extjs来开发,但是,一定要学习、研究它,研究它之后才会晓得,我们写代码应当这么写才优美、才合适。研究了它后就应当选一款轻量型的框架了。然后自己写组件。用以取代:Ext.Window、Ext.TabPanel、E
6、xt.Panel这些好东西。研究了extjs,我敢说:一览众山小啊!什么prototype、dojo、jQuery之类,就容易多了。真正要用的ajax框架,我看,倒不如选择prototype,它是个轻量型,我觉得,一个ajax,只要封装了三个东西就行了:一、Element。把dom元素要封装一下,加入动画、求取、设置各种参数值的功能二、XMLHttpRequest,要把它封装一下,这个所有框架都做了三、把事件机制要封装一下,最好像extjs一样,xxx.on(click,function();就成了。有了这三个就差不多了,那些什么window、tabs,网上多的是代码,搞些下来改篇改篇就成了。
7、关于prototype,我找到了它的中文文档(1.5的),1.5的大小是93.7k,事实上,这个大小还可以缩小,可以使用工具去掉多余的空格,差不多了。3. Ext.form概述Ext.form中封装了是输入组件。input、textArea、frameSet、form等元素都被包装起来了。我刚才发了点时间对它的类图分析了一下,用StartUML做了图如下:Ext.form中的组件太多,实在不大4. Ext.TabPanel篇Ext.TabPanel这个东西是最常用的组件之一,它继承自Ext.Panel。看了一个下午的源代码,对它的一些基本原理有所了解了。下面要讲一些问题,这些问题绝对是本人独门
8、秘笈,非入室弟子不传。哈哈哈。一、组件的组成:因为继承自Ext.Panel,所以,它也是由header、tbar、body、bbar、footer这几个部分构成,有人问:TabPanel的面板标签是在哪儿呢(就是你点击换页的东西)?它默认是放在header中的。但是,如果设置了:tabPosition的话就不一定了,tabPosition可取两个值:top、bottom。所以,标签可以是放在下面,但是,Ext目前还不支技放在左边、右边。那么,不同的标签是用什么元素来组织的呢?用ul。一页对应一个li。li的id的取值有规律哦,它的取值公式如下:tabpanel.id+tabpanel.idDe
9、limiter+面板的id。正是因为有了这个规律,才能根据点击的标签而找到对应的面板。这个问题是一大主题,在下面讲。这是面板的标签,下面的面板呢?简单!一个Ext.Panel对应一个面板,注意:这儿的面板是没有header的,如果你想tab.items.get(1).header,在这儿,header=undefined。为什么为面板定义的title会对应到标签中去呢?这个是TabPanel的特意处理的。至于换页效果是怎么出来的?CardLayout。这下组件的大概结构都清楚了。还有不明白,自己new Ext.TabPanel()一个,然后在FireBug下面去查看dom结构,就一清二楚了。二
10、、处理标签的事件为什么要研究这个问题?有需求的,如何在鼠标移到标签上时就显示对应的面板呢?默认情况下,TabPanel是不支持这个功能的,但是,这个功能有时是需要的。这儿有点小技巧。看Ext.TabPanel源代码中关于标签的事件处理: this.strip.on(mousedown, this.onStripMouseDown, this); this.strip.on(click, this.onStripClick, this); this.strip.on(contextmenu, this.onStripContextMenu, this); if(this.enableTabScr
11、oll) this.strip.on(mousewheel, this.onWheel, this); 这段代码写在initEvents函数中,先解释一下,this.strip是指头部放标签的那个ul元素,相信,98%的读者会想,要注册事件也应当是为li元素注册,怎么会统统注册到ul这个父容器上面呢?原理就是事件冒泡。关于事件传递的原理,本人在下一文中有详细的实验、明确的结论,不再赘言。ul元素捕获了事件,怎样在事件处理函数中得知倒底是哪个li发生了事件呢?Ext写了个函数:findTargets。详情请见如下代码: findTargets : function(e) var item = n
12、ull; var itemEl = e.getTarget(li, this.strip); if(itemEl) item = this.getComponent(itemEl.id.split(this.idDelimiter)1); if(item.disabled) return close : null, item : null, el : null ; return close : e.getTarget(.x-tab-strip-close, this.strip), item : item, el : itemEl ; , / private onStripMouseDown
13、: function(e) e.preventDefault(); if(e.button != 0) return; var t = this.findTargets(e); if(t.close) this.remove(t.item); return; if(t.item & t.item != this.activeTab) this.setActiveTab(t.item); ,一切的关键就在于li元素的id的命名规则,从中取出对应的面板的id,这样就能getComponent,从而获得对应的面板引用,再setActiveTab就办成了。至于getTarget这个是EventObje
14、ct中封装的函数,作用是在事件传播路径上查找满足指定选择条件的元素。这个函数的详情见它的源码。到了这里,之前所讲的鼠标悬停问题只要依照方面方法解决就是了,切记,不要处理mouseout事件,不然,事情就麻烦了,详情见我以前写过的关于mouseover事件的一篇文章。5. Function扩展篇ExtJs对JavaScript的内建对象进行了扩展,对什么Object、Date、Array、Function、String的扩展,扩展方法想必诸位都烂熟于心了:用prototype的办法。这一篇讲一讲Function扩展的精妙之处,之所以突然研究这个问题,是因为我在研究Ext.data.Store的源
15、代码时,看到一行代码:this.reader.onMetaChange = this.onMetaChange.createDelegate(this);当初,我在研究Ext.js中的代码时,对于Function的几个扩展想不透、看不明,今日大悟。且见扩展的源代码: createDelegate : function(obj, args, appendArgs) var method = this; return function() var callArgs = args | arguments; if(appendArgs = true) callArgs = Array.prototyp
16、e.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); / s
17、plice them in return method.apply(obj | window, callArgs); ; ,createDelegate函数的作用是,为指定函数创建一个回调函数,注意是创建一个新的函数返回,它返回的是一个新函数。我以前一直不明白,为什么要这么做,就像上面红色的那行代码,相信大伙与我一样,都在想,为什么不是写成这样:this.reader.onMetaChange=this.onMetaChange;不是应当这样写的吗?如果用过dotnet,那么委托一定是晓得了,javascript中的函数跟c#的委托一样,有很相近的意义,为什么c#中能这样写,JavaScrip
18、t中不能这样写呢?一切都因为this,this这个东西见风使舵,像上面onMetaChange这函数,实际调用时是在reader中,那么如果onMetaChange中使用了this关键字,那么,this是指向reader的,而不是指向onMetaChange的定义环境所对应的this。而事实上,我们往往想把这个this指向函数的定义环境,这也正是回调的最招人喜欢的地方,然而,因为this的问题,回调就不能像上面那样直接赋值。还得做些手脚,得让函数调用时scope为当前定义环境。改变一个函数执行的scope,熟翻JavaScript的兄弟一定晓得要用:call、apply。至此,createDe
19、legate的产生背景、作用都作了个交代。createDelegate(this),调用时,一般直接传个this就行了,当真是妙啊。事实上,我上面讲的一通道理清楚了,这个函数的代码就没有秘密可言了。关键就是一个this。我现在感叹,你对JavaScript的造诣与你对this的领悟层次成正比。既然讲了createDelegate,其他几个扩展函数一并讲了。 createCallback : function(/*args.*/) / make args available, in function below var args = arguments; var method = this; r
20、eturn function() return method.apply(window, args); ; 也是创建调用者的回调,不过,回调函数的scope为window。相当于createDelegate(window)。没什么讲的。 defer : function(millis, obj, args, appendArgs) var fn = this.createDelegate(obj, args, appendArgs); if(millis) return setTimeout(fn, millis); fn(); return 0; ,此函数调用一次就让函数延迟调用一次。对se
21、tTimeout的封装罢了。如果没有定义延时参数,那么就马上执行。这个函数也没有技术性可言。 createSequence : function(fcn, scope) if(typeof fcn != function) return this; var method = this; return function() var retval = method.apply(this | window, arguments); fcn.apply(scope | this | window, arguments); return retval; ; ,这个函数就有点意思了,刚开始研究ext.js
22、的时候还没有看明白,它的作用是在返回一个函数,此函数先调用“调用函数”,后调用传递进来的函数。这句话可能还没说清,见示例如下:function A()alert(第一个执行!);return 1;function B()alert(第二个执行!);return 2;function C()alert(第三个执行!);return 3;var D=A.createSequence(B).createSequence(C);var result=D();上面代码产生的效果是:第一弹出框显示:第一个执行!第二弹出框显示:第二个执行!第三弹出框显示:第三个执行!result的值为:3。这下子诸位都明白
23、了吧。用过dotnet的知道,委托变量有这种类似的功能。就是累加执行的效果。 createInterceptor : function(fcn, scope) if(typeof fcn != function) return this; var method = this; return function() fcn.target = this; fcn.method = method; if(fcn.apply(scope | this | window, arguments) = false) return; return method.apply(this | window, argu
24、ments); ; 这个函数也有点意思,有创意,它返回被调用函数的回调,这个回调是条件执行的,执行条件是createInterceptor传入的那个函数返回真。示例代码如下:function A()var B=A.createInterceptor(function(i)return i0;);B(1),则A被执行,如果调用B(-1),A则不被执行。B的作用就是如果传入的第一个参数的值大于0时A才被执行,否则不执行。相当于原有函数的功能不变,只是加个执行条件。这个想法着实巧妙。这一招现在想来,也可以用到c#中。6. Ext.data.Store篇Ext.data.Store,这个东西是Java
25、Script版的DataTable啊。貌似其他Ajax框架都没有这个玩意啊。可见啦,Ext是真的打算把b/s开发重新变成c/s开发啊。哈哈哈。便宜我等了。待某细研之。Store类提供对记录集(Record)的包装,通过前面的研究可知,DataProxy取数据(url或数组或xml或json),DataReader用于从不规范的数据取出并格式化指定结构的记录集。记录的结构由Record.create创建。DataProxy通过对Connection的调用取得数据(Response)后,在回调中调用DataReader的read函数,从而把response中的数据解析成记录集,这个记录集将再以回调
26、参数的形式传出来,store实现这个回调,并把里面的Recodrd取出来,放到data这个成员中。store.data是一个MixedCollection对象,MixedCollection作什么用的前面也讲过,它本质就是一个容器,ExtJs确实很好,连容器类都写了。有了store.data,数据进了这儿,就好办了,store调用MixedCollection的功能,实现了一些通用的函数,如取指定成员、查询、遍历、事务等等,这些都不足道。什么提交修改、取消修改的功能却是根源于Record。Record类自身就封装了这个功能,Store中只是再次封装罢了,这个原理也很简单。看代码即知。上面讲的是
27、通用原理,是大概,下面拣紧要的代码说一下。它定义了构造函数,继承自Ext.Observable。第一行代码就是个重点:this.data = new Ext.util.MixedCollection(false);这是定义data,所有记录都将保存在它里面。 this.baseParams = ; / private this.paramNames = start : start, limit : limit, sort : sort, dir : dir ;baseParams将在调用HttpProxy时用到,它将作为params附加到url末尾。这个东西没有悬念。至于paramsNames用于保存参数名,start、limit应当用于分页,sort、dir用于排序,不过,我看了通篇的代码,发现,Store本身不提供任何其他分页、排序功能的实现,还是得依靠服务器端的。只不过,这儿提供一种统一的方式罢了。 if(config & config.data) this.inlineData = config.data; delete config.data; 意思是说,如果创建store时,设了config,且config.data存在,那么,将直接从config.data中loadData。构造函数后面一点就
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1