28.2. 渲染机制介绍

OperaMasks 2.3及以前版本中构件渲染机制不统一,存在多种渲染方式,一些构件与另一些构件的渲染方式可以差别很大,用户要定义自己的构件时,往往不知道应该参考哪一套机制,或者没明白渲染机制中的原理就盲目参考,导致定义出来的构件基本不可用。

OperaMasks 3.0版本对所有构件的渲染机制进行了统一,提供统一的基类和接口,所有构件渲染器采用同一套机制来写,结构清晰,用户参考任何一个构件的渲染器都可以定义出自己的构件或渲染器。并且3.0版本中极大地减少了Annotation使用,使用渲染的效率也得到了提高。

统一后的继承体系如下图:

OperaMasks渲染机制继承图

图 28.1. OperaMasks渲染机制继承图


其中最上面的Renderer是JSF中规定的所有渲染器的基类,只有继承自这个类才能称得上是渲染器。HtmlBasicRenderer是一个接口,此接口提供渲染出HTML代码的方法。ResourceRenderer是一个接口,它提供渲染JavaScript代码的方法。HtmlBasicRendererBase是所有Render-Kit是Html-Basic的渲染器的基类,它实现了HtmlBasicRenderer和ResourceRenderer接口,因而能在非AJAX情况下构件的渲染HTML代码和JavaScript代码。AjaxRenderer是一个接口,这提供在AJAX情况下进行AJAX渲染的方法。AjaxRendererBase是所有Render-Kit是AJAX的渲染器的基类,因为AJAX渲染器在首次请求时一般也要渲染出一些HTML代码和JavaScript代码,所以它继承自HtmlBasicRendererBase,同时它还实现了一个PartialUpdateRenderer接口。PartialUpdateRenderer接口提供局部渲染(OperaMasks 3.0的一个新特性)相关的方法。

简单说来,我们要定义一个渲染器,只要直接或间接继承自HtmlBasicRendererBase或AjaxRendererBase就可以了。如果要构件工作在AJAX下(即页面中f:view的renderKitId="AJAX"),就继承自AjaxRendererBase。如果构件要工作在Html-Basic下,就继承自HtmlBasicRendererBase。继承之后只需要根据实际需要覆写其中的一些方法就可以了。

我们来看一下这两个渲染器基类中有哪些方法可以覆盖。Html-Basic渲染器中有以下方法:

而且各方法执行的先后顺序与上面的排序一致。我们来看一段代码:

<w:panelBox>
    <w:form>
        <w:button />
    </w:form>
</w:panelBox>

其中w:button的getEncodeHtmlChildren()和getEncodeResourceChildren()方法返回的是true,其它构件这两个方法都是返回false,那么在渲染时上面那些方法调用的先后顺序是这样的:

w:panelBox的渲染器的encodeHtmlBegin
w:form的渲染器的encodeHtmlBegin
w:button的渲染器的encodeHtmlBegin
w:button的渲染器的encodeHtmlChildren
w:button的渲染器的encodeHtmlEnd
w:form的渲染器的encodeHtmlEnd
w:panelBox的渲染器的encodeHtmlEnd

w:panelBox的encodeInitScriptBegin
w:form的渲染器的encodeInitScriptBegin
w:button的渲染器的encodeInitScriptBegin

w:panelBox的encodeResourceBegin
w:form的encodeResourceBegin
w:button的encodeResourceBegin
w:button的encodeResourceChildren
w:button的encodeResourceEnd
w:form的encodeResourceEnd
w:panelBox的encodeResourceEnd

w:button的渲染器的encodeInitScriptEnd
w:form的渲染器的encodeInitScriptEnd
w:panelBox的encodeInitScriptEnd

我们再看一看AJAX渲染器有哪些方法,AjaxRendererBase类继承自HtmlBasicRendererBase,所以AJAX渲染器也有上面的那些方法。因为Render-Kit="AJAX"的首次渲染是GET请求,属于非AJAX的,与上面的Html-Basic渲染器一样,也执行那些方法,执行的先后顺序也是一样的。

而Render-Kit="AJAX"的非首次请求是POST请求,是AJAX的,它会执行一些AjaxRendererBase中实现自AjaxRenderer接口的方法,同时OperaMasks 3.0中为AJAX渲染器提供局部渲染的功能,AjaxRendererBase中还有一些PartialUpdateRenderer接口实现的方法。具体有以下方法

而且各方法执行的先后顺序为:encodeAjaxBegin()-->getEncodeAjaxChildren()-->encodeAjaxChildren()(如果getEncodeAjaxChildren()返回true才会执行)-->encodeAjaxEnd(),下面三个方法在引擎内部自动调用。还是那段代码:

<w:panelBox>
  <w:form>
    <w:button />
  </w:form>
</w:panelBox>

其中w:button的getEncodeAjaxChildren()方法返回的是true,其它构件这个方法都是返回false,那么在AJAX请求的渲染时上面那些方法调用的先后顺序执行这些方法:

w:panelBox的渲染器的encodeAjaxBegin
w:form的渲染器的encodeAjaxBegin
w:button的渲染器的encodeAjaxBegin
w:button的渲染器的encodeAjaxChildren
w:button的渲染器的encodeAjaxEnd
w:form的渲染器的encodeAjaxEnd
w:panelBox的渲染器的encodeAjaxEnd

总之,Html-Basic渲染或AJAX的首次渲染时,构件的渲染器会按顺序执行HtmlBasicRendererBase的各个方法。AJAX的非首次渲染时会按顺序执行这些方法:encodeAjaxBegin()-->getEncodeAjaxChildren()-->encodeAjaxChildren()(如果getEncodeAjaxChildren()返回true才会执行)-->encodeAjaxEnd()。