• Qomo之快速上手



    Qomo之快速上手
    -----

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

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

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


    一、装载Qomo
    -----

    我们计划在将来为各种JavaScript应用环境加入一个定制的loader,用来装入Qomo
    的其它部分。但现在,Qomo还主要是用在浏览器中。所以他的装载代码是这样:
    1. <!-- in test.html -->
    2. <script src="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. function MyObject() {
    3.   // ..
    4. }
    5. // 2. 类注册(创建这个类TMyObject)
    6. TMyObject = Class(TObject, 'MyObject');

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


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

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

    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. <script src="js/Qomo.js"></script>

    3. <body>
    4.   <input id="pwd" value="my password in here">
    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. <script src="js/Qomo.js"></script>

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

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

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

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

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

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

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

    9.   this.getvalue =
    10.   this.getValue = function() {
    11.     return this.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. var ed = TLabledEdit.Create('edLabled');
    2. alert( ed.get('LableText') );
    3. ed.set('LableText''my lable:');
    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.   <fieldset id="edLabled2">
    3.     <legend>请输入:</legend>
    4.     <input name="edit" value="...">
    5.   </fieldset>
    6. </body>

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

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

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

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


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

    8. <!-- yui component, code copy from yui examples -->
    9. <body class="yui-skin-sam">
    10.   <h3>Enter a state:</h3>
    11.   <div id="myAutoComplete">
    12.     <input id="myInput" type="text">
    13.     <div id="myContainer"></div>
    14.   </div>

    15. <script type="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.     // Use a LocalDataSource
    28.     var oDS = new YAHOO.util.LocalDataSource(YAHOO.example.Data.arrayStates);
    29.     // Optional to define fields for single-dimensional array
    30.     oDS.responseSchema = {fields : ["state"]};

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

    2. <!-- load qomo -->
    3. <script src="js/Qomo.js"></script>

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

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

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


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

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

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

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

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

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

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

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

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

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

    4. function doStateChange(state) {
    5.   if (state != 4) return;  // wait downloaded.

    6.   var ajx = this.get('XMLHTTP');
    7.   if (ajx.status!=200 && ajx.status!=304 && ajx.status!=0) return;  // staus is failed.

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

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

    5. <script>
    6. function doAction(ord, url, ctx) {
    7.   var txt = document.getElementById('txt');
    8.   var str = 'machie(%s) to process a url/n/
    9.    - Url: %s /n/
    10.    - Length: %s /n/n';

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

    13. function doStateChange(state) {
    14.   if (state != 4) return;  // wait downloaded.

    15.   with (this.get('XMLHTTP')) {
    16.    switch (status) {
    17.      case 200:
    18.      case 304:
    19.      case 0:
    20.        doAction(this.id, this.data.src, responseText); break;
    21.      default:
    22.        // staus is failed.
    23.        alert('failed: ' + status)
    24.     }
    25.   }
    26. }

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

    33. // 池化管理 - 创建处理池(允许最多3个处理机实例),并填入数据
    34. var pool = new Pool(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

  • 相关阅读:
    C++重载运算符
    std::vector
    new、delete、动态数组初始化、野指针、解引用、内存池、重载new和delete、内存泄漏等,释放崩溃
    C++匿名函数lambda
    缺少wntdll.pdb
    map、multimap和unordered_map(hash_map)以及unorderd_multimap
    分享一个双击后编辑并AJAX提交保存的脚本
    jquery.cookie.js操作cookie
    MVC获得某个View 或者 PartialView 生成的字符串
    c#中using 和new
  • 原文地址:https://www.cnblogs.com/encounter/p/2188620.html
Copyright © 2020-2023  润新知