Qomo之快速上手


Qomo之快速上手
-----

我发现,无论是哪种成功的语言,总是有一个快速入门的读物,而无论它们本身是
如何的复杂、艰涩或难于理解。反过来,不成功的语言,总是带有一堆技术性十足、
充满了想象和预期的文档。后者的这些文档,有些甚至比代码还多,但是这同样未
能挽救它们的失败。

于是,我同样地看到了Qomo。我发现Qomo发布过的文档中,总是有大量无法让人理
解的东西。如果你准备写一门语言,那么可能Qomo的文档和代码会给你许多启发。
而如果你只是打算用它,那么大概会变得很痛苦。然而,如果一个人因为想写一门
语言而去了解Qomo,那么他大概不会再使用Qomo,这是因为各自存有不同的目标。

于是,我想Qomo小组应该为“一个普通的使用者”而写一些东西。例如现在这篇。


一、装载Qomo
-----

我们计划在将来为各种JavaScript应用环境加入一个定制的loader,用来装入Qomo
的其它部分。但现在,Qomo还主要是用在浏览器中。所以他的装载代码是这样:
  1. <!--intest.html-->
  2. <scriptsrc="js/Qomo.js"></script>

在这个示例中,我们假设你网站中的文件是按如下方式组织的:
  1. <your_site>\test.html
  2. <your_site>\js\Qomo.js
你可以将整个Qomo放在js目录下。这样它会是如下的目录结构:
  1. <your_site>\js\Build\*.*
  2. <your_site>\js\Components\*.*
  3. <your_site>\js\Framework\*.*
  4. <your_site>\js\Qomo.js
或者你也可以使用一个编码(压缩+混淆)过的版本,这会是一个独立的文件。


二、创建一个类,及其实例
-----

Qomo主要扩展了一些面向对象的语法。最简单的用法,总是包括一个类注册的函
数。例如:
  1. //1.声明一个构造器
  2. functionMyObject(){
  3. //..
  4. }
  5. //2.类注册(创建这个类TMyObject)
  6. TMyObject=Class(TObject,'MyObject');

  7. //3.创建实例的两种(效果上是一样的)
  8. obj1=newMyObject();
  9. obj2=TMyObject.Create();
其中,TObject是Qomo类继承中关系中的基类。如果你构造更深层次的类,那么Class()
的第一个参数也可以TMyObject,或者其它任何的、Qomo识别的类。


三、如果你想为对象添加一些私有的属性(attributes)
-----
如果你想这样做,那么你找对了东西,Qomo天生就是这种“私有”和“稳藏”而
设计的。这在上面的代码中,修改一下构造器就可以做到:
  1. //构造器
  2. functionMyObject(){
  3. Attribute(this,'Name','MyObject','r');
  4. Attribute(this,'Size',100);
  5. }
  6. //类
  7. TMyObject=Class(TObject,'MyObject');

  8. //实例
  9. obj1=newMyObject();
  10. obj2=newMyObject();

  11. //两个实例的私有属性不同
  12. obj1.set('Size',20);
  13. alert(obj1.get('Size'));//20
  14. alert(obj2.get('Size'));//100


四、让Qomo在网页中变得更有用
-----
对于网页制作者来说,他们关心的只是网页中如何方便地使用Qomo,而并不是上面这些类、
子类如何创建。大多数情况下来说,的确如此。

而简单地说来,我们可能在关心在网页中如何存取一个页面上的东西,比如一个用ID标识
的对象。在Qomo中,这比较方便。
  1. <!--demo.html-->
  2. <scriptsrc="js/Qomo.js"></script>

  3. <body>
  4. <inputid="pwd"value="mypasswordinhere">
  5. </body>

  6. <script>
  7. //(*注)
  8. //$import('Components/Components.js');

  9. el=THtmlController.Create('pwd');
  10. alert(el.get('value'));
  11. </script>
(*注)在V2.1以前版本的Qomo缺省核心库中是不包括Components.js的。这种情况下需要使
用$import()来装载Components。但目前你正使用的这个版本,应该已经缺省包含了。在任
何情况下,你可以自行发布一个Qomo的集成(build)版本。这需要你用Qomo包中的:
Build\TestCase\T_CustomBuilder.html
来产生一个自己需要的Qomo代码包。记得选中“载入扩展界面控件”就好了。

上面这个例子说明,你可以为任意界面上的HTML元素添加一个THtmlController控制。它封
装了界面上的HTML元素的一些细节,如果你需要访问原始的HTML属性,那么使用el.get()
就可以了。

五、让Qomo做一个Html的控件
-----
更进一步的说,你可以将任何界面上的一组Elements封装成为一个Qomo的类。这个类可以认
识界面上的这些组合在一起的东西是一个控件,或者其它。一个较为浅显的例子是:我们可
以将一个div与一个edit放在一起,使它变成一个TLabledEdit。这是个不错的主意:
  1. <scriptsrc="js/Qomo.js"></script>

  2. <body>
  3. <divid="edLabled"><span>hello,TLabledEdit.</span><br>
  4. <inputname="edit"value="...">
  5. </div>
  6. </body>

  7. <script>
  8. //后续将说明的代码
  9. //……
  10. </script>

那么我们到底如何将它实现为一个Html控件呢?首先,我们要在准确地找到所有要控制的
元素。下面是这样的一个基本框架:
  1. functionLabledEdit(){
  2. Attribute(this,'_label',null,'r');
  3. Attribute(this,'_edit',null,'r');

  4. this.get_label=function(){
  5. returnthis.assignedElement.children(0);
  6. }
  7. this.get_edit=function(){
  8. returnthis.assignedElement.children('edit');
  9. }

  10. //..其它的实现代码
  11. }

接下来,我们可以尝试为这个控件添加几个特性,以直接控制界面上的东西:
  1. functionLabledEdit(){
  2. //(略,同上...)

  3. this.getLableText=function(){
  4. returnthis.get('_label').innerText;
  5. }
  6. this.setLableText=function(v){
  7. this.get('_label').innerText=v;
  8. }

  9. this.getvalue=
  10. this.getValue=function(){
  11. returnthis.get('_edit').value;
  12. }

  13. this.setvalue=
  14. this.setValue=function(v){
  15. this.get('_edit').value=v;
  16. }
  17. }

然后注册它:
  1. TLabledEdit=Class(THtmlController,'LabledEdit');
然后我们来看看效果:
  1. vared=TLabledEdit.Create('edLabled');
  2. alert(ed.get('LableText'));
  3. ed.set('LableText','mylable:');
  4. ed.set('Value','hello,world.');

六、如此麻烦地做一个组件有什么价值?
-----
有什么价值呢?如果我们的确需要控制这么一个“看起来象组件的HTML代码块”,那么
我们直接用几行脚本就可以办到。例如:
  1. document.getElementById('edLabled').children(2).value='hello,world.';
  2. //...

然而,组件系统的真正价值在于复用,类继承的价值亦复如此。如果偏离了复用来讨论
上述的一切,那无异于隔靴搔痒。我们来想象一下,如果我们需要一个使用FieldSet来
做标签的edit,那么又该如何做呢?更多的Editor?

好,我们在Qomo中基于上面的TLabledEdit代码来做一个。
  1. <body>
  2. <fieldsetid="edLabled2">
  3. <legend>请输入:</legend>
  4. <inputname="edit"value="...">
  5. </fieldset>
  6. </body>

  7. <script>
  8. functionFieldSetEdit(){
  9. }
  10. TFieldSetEdit=Class(TLabledEdit,'FieldSetEdit');

  11. //示例
  12. vared=TFieldSetEdit.Create('edLabled2');
  13. ed.set('Value','hello,world.');
  14. </script>
真的吗?!FieldSetEdit实现时不需要任何的代码?!

是的。尽管两个组件的表达形式完全不一样,但是由于我们分离了逻辑实现与界面表
面,所以我们只需要调整少数(甚至于象这样无需修改)就可以适应变化了。

Oh。有高手看出来了,我实际上偷了个懒:这里的edLabled2的“HTML结构”与前一
种没有本质的不同。是的,好吧,为了让你相信Qomo具有“节省代码”的能力,那么
我们就弄复杂一点。


七、将一个控制层的组件,复用在其它框架库中
-----
我们找一个相对复杂的Edit,例如我们拿一个YahooUI中的、能自动完成的Edit。大概,
我们要装入一个YahooUI,然后初始化它。最后,再装入我们的代码。OK,就象这样:
  1. <!--loadyui-->
  2. <linkrel="stylesheet"type="text/css"href="yui/build/fonts/fonts-min.css"/>
  3. <linkrel="stylesheet"type="text/css"href="yui/build/autocomplete/assets/skins/sam/autocomplete.css"/>
  4. <scripttype="text/javascript"src="yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
  5. <scripttype="text/javascript"src="yui/build/animation/animation-min.js"></script>
  6. <scripttype="text/javascript"src="yui/build/datasource/datasource-min.js"></script>
  7. <scripttype="text/javascript"src="yui/build/autocomplete/autocomplete-min.js"></script>

  8. <!--yuicomponent,codecopyfromyuiexamples-->
  9. <bodyclass="yui-skin-sam">
  10. <h3>Enterastate:</h3>
  11. <divid="myAutoComplete">
  12. <inputid="myInput"type="text">
  13. <divid="myContainer"></div>
  14. </div>

  15. <scripttype="text/javascript">
  16. YAHOO.example.Data={
  17. arrayStates:[
  18. "Alabama",
  19. "Alaska",
  20. "Arizona",
  21. "Arkansas",
  22. "California",
  23. "Colorado",
  24. "Connecticut"]
  25. };

  26. YAHOO.example.BasicLocal=function(){
  27. //UseaLocalDataSource
  28. varoDS=newYAHOO.util.LocalDataSource(YAHOO.example.Data.arrayStates);
  29. //Optionaltodefinefieldsforsingle-dimensionalarray
  30. oDS.responseSchema={fields:["state"]};

  31. //InstantiatetheAutoComplete
  32. varoAC=newYAHOO.widget.AutoComplete("myInput","myContainer",oDS);
  33. oAC.prehighlightClassName="yui-ac-prehighlight";
  34. oAC.useShadow=true;
  35. return{
  36. oDS:oDS,
  37. oAC:oAC
  38. };
  39. }();
  40. </script>
  41. </body>
  42. <!--endofyuiload-->
OH! 这么多代码~~ 不过都是Yahoo UI的。Qomo要做的事则很简单:
  1. <!--续上例-->

  2. <!--loadqomo-->
  3. <scriptsrc="js/Qomo.js"></script>

  4. <!--ourscomponentanddemo-->
  5. <script>
  6. functionLabledEdit(){
  7. //(同上,略...)
  8. }
  9. TLabledEdit=Class(THtmlController,'LabledEdit');

  10. //新的TYuiEdit组件
  11. YuiEdit=function(){
  12. this.get_label=function(){
  13. returnthis.assignedElement.previousSibling;
  14. }
  15. this.get_edit=function(){
  16. returnthis.assignedElement.children.tags('input')(0);
  17. }
  18. }
  19. TYuiEdit=Class(TLabledEdit,'YuiEdit');

  20. //以下示例代码
  21. vared=TYuiEdit.Create('myAutoComplete');
  22. alert(ed.get('LableText'));
  23. ed.set('Value','hello,world.');
我们的示例代码,也就是应用程序的逻辑部分,相对于我们前面使用TLabledEdit的例子来说,并
未发生改变。而我们使用了非常复杂的——当然我也认为是非常不错的——Yahoo UI组件。


六、构造更深层次的类
-----
如同上面的示例一样,我们总有可能在JavaScript中使用继承层次很深的类。如果并且JavaScript自
身的(原型继承的)方法来实现,那么我们需要调用父类的方法时就会比较麻烦。而在Qomo中,扩展
了调用父类方法的inherited(),使得这个过程变得很简单。
  1. //构造器
  2. functionMyObject(){
  3. Attribute(this,'Size',100);
  4. }

  5. functionMyObjectEx(){
  6. this.getSize=function(){
  7. return2*this.get();//<-在特性(attribute)读写器(方法)中调用缺省的或父类的读写方法
  8. }

  9. this.aMethod=function(){
  10. alert('hi,inMyObjectEx');
  11. }
  12. }

  13. functionPowerObject(){
  14. this.aMethod=function(){
  15. this.inherited();//<-在方法中调用父类方法
  16. alert('hi,inPowerObject');
  17. }
  18. }

  19. //类注册
  20. TMyObject=Class(TObject,'MyObject');
  21. TMyObjectEx=Class(TMyObject,'MyObjectEx');
  22. TPowerObject=Class(TMyObjectEx,'PowerObject');

  23. //示例
  24. obj=newMyObjectEx();
  25. pw=newPowerObject();
  26. alert(obj.get('Size'));
  27. pw.aMethod();

七、我需要Ajax!
-----
当然,我知道很多人需要Ajax,尽管也有相当一部分人不知道为什么他们需要。事实上,在
Qomo中的Ajax用起来很简单。
  1. ajx=newAjax();

  2. ajx.open("GET",'http://www.sina.com.cn/',false);
  3. ajx.send(null);

  4. text=ajx.responseText;
  5. alert('thepagesizeis:'+text.length);
不错,很多人能看出来这只是对XMLHttpRequest的一个简单封装。所以知道这一点的人也明
白如何用一个函数来响应ajx.onreadystatechange,以及使用ajx中的'POST'方法来获取一
个远程数据。因此我就不细讲这些内容了,下面讨论Qomo中一个更有用的封装:Ajax池。

其实它真实的名字,是叫HttpGetMachine。我们先看一下不使用Ajax池的情况:
  1. functiondoAction(url,ctx){
  2. alert('Url:%s\nLength:%s'.format(url,ctx.length));
  3. }

  4. functiondoStateChange(state){
  5. if(state!=4)return;//waitdownloaded.

  6. varajx=this.get('XMLHTTP');
  7. if(ajx.status!=200&&ajx.status!=304&&ajx.status!=0)return;//stausisfailed.

  8. doAction(this.data.src,ajx.responseText);
  9. }

  10. //测试,不使用Ajax池
  11. varajx=newHttpGetMachine();
  12. ajx.OnStateChange.add(doStateChange);
  13. ajx.data={src:'http://www.sina.com.cn/'};
  14. ajx.OnStateChange('resume');
使用Ajax池也没什么复杂的:
  1. <!--在网页中,用于显示输出-->
  2. <body>
  3. <textareaid="txt"style="width:800px;height:600px"></textarea>
  4. </body>

  5. <script>
  6. functiondoAction(ord,url,ctx){
  7. vartxt=document.getElementById('txt');
  8. varstr='machie(%s)toprocessaurl\n\
  9. -Url:%s\n\
  10. -Length:%s\n\n';

  11. txt.value+=str.format(ord,url,ctx.length);
  12. }

  13. functiondoStateChange(state){
  14. if(state!=4)return;//waitdownloaded.

  15. with(this.get('XMLHTTP')){
  16. switch(status){
  17. case200:
  18. case304:
  19. case0:
  20. doAction(this.id,this.data.src,responseText);break;
  21. default:
  22. //stausisfailed.
  23. alert('failed:'+status)
  24. }
  25. }
  26. }

  27. //pool的处理函数.id仅用于识别在处理中的mac序号,不是必须的.
  28. varid=1;
  29. functiondoOnStateChange_pool(mac,state){
  30. if(!mac.id)mac.id=id++;//为machine做一个标识
  31. doStateChange.call(mac,state);
  32. }

  33. //池化管理-创建处理池(允许最多3个处理机实例),并填入数据
  34. varpool=newPool(THttpGetMachine,3);
  35. pool.OnStateChange.add(doOnStateChange_pool);
  36. pool.push({src:'http://www.sina.com.cn/'});
  37. pool.push({src:'http://www.snda.com.cn/'});
  38. pool.push({src:'http://www.tom.com/'});
  39. pool.push({src:'http://www.google.com/'});
  40. //more...
  41. </script>

Ajax池实质上是帮助用户管理THttpGetMachine的创建与调度,由pool来决定什么时候传给
哪个具体的Machine以数据,并如何响应这个数据的处理状态。


九、其它的东西
-----
Qomo V2.1将原来的LocalDB、Graphi等全部从代码包中移除了,我们将重写它。这个工作很快
就会开始。仅从复杂性上讲,V2.1有一个不错的开端,为此我们还移除了现有的大多数Controls。

Qomo V2.x有一个并行的项目,叫QoBean。QoBean目前还没有发布一个正式版本,但它已经有非
常好的表现:它比Qomo少%30多的代码,但性能却提供了30~40%。这个版本将会合并到Qomo V3中
去,以替代现有的Qomo内核。

Qomo中有一些小工具,例如Common\ParserLite.js,以及TimeMachine.js(不是时光穿梭机啊)。
还有一些用于检测效率,例如Debug\TestCase\RegExpPerformanceTool.html。当然,最重要的,
还是位于根目录下的Build工具,和一个相对无素的示例:Samples.html。

在FF3里,你必须使用根目录下的Samples.html来launch其它的演示,而不能从硬盘上直接打开
它们。这是因为FF3调整了本地文件的Ajax存取安全性设定。

在Qomo里,对象还有一些更为复杂的用法。例如注册接口,以及切面系统等。这些比较高级的用法,
你可以在Qomo的代码包中去查找示例,或者在Blog中找到有关机制的说明文档。

直接下载发布包:

http://download.csdn.net/source/689574

http://download.csdn.net/source/689579


Qomo最新的代码:
https://qomo.svn.sourceforge.net/svnroot/qomo/trunk

QoBean最新的代码:
https://qomo.svn.sourceforge.net/svnroot/qomo/qobean

你可能感兴趣的:(JavaScript,Ajax,css,Yahoo,yui)