• Qomolangma实现篇(九):Qomo中的模板系统


    ================================================================================
    Qomolangma OpenProject v1.0


    类别    :Rich Web Client
    关键词  :JS OOP,JS Framwork, Rich Web Client,RIA,Web Component,
              DOM,DTHML,CSS,JavaScript,JScript

    项目发起:aimingoo (aim@263.net)
    项目团队:../../Qomo_team.txt
    有贡献者:JingYu(zjy@cnpack.org)
    ================================================================================ 

    一、模板技术概要
    ~~~~~~~~~~~~~~~~~~
    模板技术由来以久。在C++中的模板(Template)是编译时技术,而在.NET CLR中用于取代该技术的
    范型(Generic)则是一种运行时技术。由于范型理论的出现,使范型编程成为一个新的语言课题。
    在.NET CLR中,范型编程就是一种用模板来实现代码重用的高效技术(类范型和方法范型)。

    然而,模板技术的使用也带来了很多的问题。例如:
      - 模板系统的出现,是为了解决了类型问题呢,还是只是解决代码重用的问题?
      - 通过模板来生成可运行代码框架,是否有利于节约代码呢?——而这种代码
       的节约又增加了多少运行效率上的开销呢?
      - 通过模板来生成框架之后,又是否可进行类型约束呢?类型约束的意义又何在呢?

    相关的问题还非常的多。因此在Qomo的设计中,曾经一度为此而迷惑。但最终,我还是在Qomo的
    内核一层加入了模板系统。


    二、Qomo内核中的模板系统
    ~~~~~~~~~~~~~~~~~~
    Qomo之所以要将Templet.js放入RTL,是希望在RTL一级支持一种全局性的模板语言,用于组织
    框架中的重复性元素,包括脚本、样式和HTML等,甚至可以通过Templet来生成类。——如同
    C++中的模板。

    javascript的确不需要为了类型问题而实现一种模板或者范型系统,因此Qomo的模板与C++的模板并
    不完全等义。这也是我使用Templet这个词,而不是Template的原因之一。这尽管是一个小小的差异,
    但也希望引起你的注意。^.^

    Templet支持一个用"%...%"格式描述的标签。如果写成"%%",则表明应该替换成单个的"%"。对于标
    签中的被替换内容,Templet默认认为它来自于模板实例的Attribute。例如:
    ----------
    function MyTemplet() {
      _set('TempletContext', '<font color="red">%Info%</font>');

      Attribute(this, 'Info', 'hello, world!');
    }
    TMyTemplet = Class(TTemplet, 'MyTemplet');

    var ctx = new MyTemplet();
    document.writeln(ctx);
    ----------

    这段代码的运行结果,是向Document输入这样一段HTML:
    ----------
    <font color="red">hello, world!</font>
    ----------

    Templet的构造器还可以接受一个参数,它可以是从Qomo的Object继承下来的任意对象。这时,Templet
    将使用该对象的,而不是模板实例的Attribute。例如与上面的例子等效的代码是:
    ----------
    function MyObject() {
      Attribute(this, 'Info', 'hello, world!');
    }
    TMyObject = Class(TObject, 'MyObject');

    function MyTemplet() {
      _set('TempletContext', '<font color="red">%Info%</font>');
    }
    TMyTemplet = Class(TTemplet, 'MyTemplet');

    var ctx = new MyTemplet(new MyObject());
    document.writeln(ctx);
    ----------

    Qomo内核中的Templet,在默认设计上与HTML标签或者其它任何特定的内容都没有关系。因此你
    可以用它来生成HTML的模板或者CSS的模板,甚至用它来生成javascript的模板并用eval()来执行。
    ——我想已经有人在开始假设这种技术能被应用到的环境了。哈哈。^.^

    三、扩展Templet系统
    ~~~~~~~~~~~~~~~~~~
    如果需要对构造器支持的这个参数的Attribute取值进行限制,例如屏蔽对一些特性(Attribute)的读取,那么
    你也可以通过公布自己的IAttrProvider接口来达到目的。

    例如:
    ----------
    function MyTemplet() {
      Attribute(this, 'Info', 'hello, world!');
      Attribute(this, 'Info2', 'hello, world!');
      _set('TempletContext', '<font color="red">%Info%, %Info2%</font>');

      var cls = _cls();
      var Intfs = Aggregate(cls.Create, IAttrProvider);
      var intf = Intfs.GetInterface(IAttrProvider);
      var has = intf.hasAttribute;
      var hasOwn = intf.hasOwnAttribute;

      intf.hasAttribute = function(n, t) {
        return (n=='Info' ? false : has.apply(intf, arguments));
      }
      intf.hasOwnAttribute = function(n, t) {
        return (n=='Info' ? false : hasOwn.apply(intf, arguments));
      }
    }
    TMyTemplet = Class(TTemplet, 'MyTemplet');

    var ctx = new MyTemplet();
    document.writeln(ctx);
    ----------
    在这个例子中,我们看到%Info%没有被替换,而%Info2%被替换了。这表明IAttrProvider接口被有
    效的重写了。

    四、Templet系统在Qomo组件框架中的使用
    ~~~~~~~~~~~~~~~~~~
    在Qomo的组件框架中,模板系统是一个很关键的核心系统。简单的说,Qomo希望通过模板系统
    来简化HTML代码的生成。同时模板系统也用于描述某个组件在DOM结构上的基本需求。

    为此,Qomo在/Components/Controls/HtmlTemplet.js中实现了一套基础的HTML模板。此外,还
    使用重写对象构造器的技术,来实现了Qomo组件与HTML中具体的Element的绑定。这里涉及到非
    常多的技术组件,但主要包括在:
       - /Components/Controls/HtmlTemplet.js
       - /Components/Controls/HtmlController.js
    这两个单元的实现中。——事实上,这两个单元是交叉作用的。

    首先,在HtmlController.js中,我们使用AOP的技术,拦截了THtmlController的构造过程,并重写
    了IAttrProvider接口。这样做的目的,是为了实现对THtmlController及其所有的子类进行影响,使
    得他们的实例可以从Qomo对象的属性(property)与特性(attribute)中来取得值,可以从这个Qomo对
    象所关联到的HTML Element的性质(HTML Attribute)中得到值。当然,为了完整地实现这个过程,
    HtmlController.js中还重写了this.get()和this.set()方法。

    现在,我们在Qomo中就可以这样写一段代码:
    ----------
    <div id='elem' class="myClass">hello, world!</div>

    <script>
    var ctrl = new HtmlController();
    ctrl.assign(document.getElementById('elem'));

    document.writeln(ctrl.get('className'));
    </script>
    ----------
    这样,我们看到输出字符串“myClass”,但是,我们并没有为THtmlController这个类声明
    “className”这样一个特性(attribute),ctrl.get()事实上是从elem这个元素中取得了值。

    由于THtmlController类具有这样的功能,因此当一个关联了HTML Element的THtmlController
    被作为一个TTemplet对象的输入之后,就可以顺理成章地将HTML Element的attributes用于
    模板系统中了。

    然而,这样仍然只是单向的功能。——也就是说,我们是为TTemplet提供了替换标签时所用的
    对象。这并不表现我们已经构造了“Qomo的组件框架的模板库”。

    这后面这个重任就是由HtmlTemplet.js来完成的了。在这个单元里,我们实现了:
      - THtmlTemplet
      - TInlineTemplet
      - TBlockTemplet
      - TTagTemplet
      - TComponentTemplet

    由于RTL已经内置了模板系统,因此事实上上面这些类的实现都非常简单。例如:
    ----------
    function TagTemplet() {
      _set('TempletContext', '<%tagName% id="%id%" class="%className%"%Attributes% />');
    }
    TTagTemplet = Class(THtmlTemplet, 'TagTemplet');
    ----------

    最后,在TComponentTemplet中,我们将组件跟样式(CSS)关联了起来。这样一来,我们就
    构成了整个Qomo的组件系统的基础逻辑:
      - HTML Element与一个THTMLController组件关联,这是表达在浏览器中的实际对象;
      - 每一个Qomo的组件可以有一个TComponentTemplet来描述该组件使用的DOM结构;
      - 由于Qomo中,通过.js的代码来操作的具体对象,是一个由TComponentTemplet约束过的
        DOM Element,所以只要其结构不变,则样式、效果的变化将不会影响到实现组件的.js代码。
      - 通过TComponentTemplet模板,我们将CSS、HTML DOM和Qomo组件关联起来,但这种
        关联非常松散,能轻易地表达“界面与逻辑分离”的UI设计思想。

    这种结构,我们可以用下面的代码表现出来(这段代码在Qomo中是可以运行的):
    ----------
    <div id='elem' class="myClass">hello, world!</div>

    <script>
    var ctrl = new HtmlController('elem');
    var temp = new ComponentTemplet(ctrl);
    alert(t);
    </script>
    ----------
    这段代码最终将显示“elem”对象作为一个Qomo组件的基本结构。

    五、其它
    ~~~~~~~~~~~~~~~~~~
    本节的内容,主要讲述模板系统,但也讲述了它对于Qomo的组件系统的价值。由于Qomo的组
    件框架基于“界面与逻辑”分离的理论来进行实践,因此我们后续的文章中,将会用更多的时间
    来讲述相关的知识,以及Qomo的实现方法。

    Qomo的最新内核代码和组件库的基础代码,近期将在开发组内发布。

    本文中没有讲述HtmlController()对象如何改变对象构造过程,也没有在代码一层,来讲述它如
    何与Templet、CSS系统关联。这些是在今后的内容中讨论的。

  • 相关阅读:
    三、单例模式
    二、工厂模式
    一、设计模式六大原则
    十二、Spring之IOC容器初始化
    PythonWeb开发教程(二),搭建第一个django项目
    PythonWeb开发教程(一),开发之前需要准备什么
    基于python的性能测试工具–locust
    在成为测试大牛的路上,我推荐BestTest
    移动端自动化测试(一)appium环境搭建
    常用工具篇(二)死链接扫描工具–Xenu
  • 原文地址:https://www.cnblogs.com/encounter/p/2188697.html
Copyright © 2020-2023  润新知