用XSL将ExtJS封装成标签

一年多以前写了一个将ExtJS(当时是2.x)封装成JSF组件的库ExtFaces,前后大概用了两个月,到目前已在公司两个不大的项目中应用,效果不错。ExtJS 3和JSF 2出来后面临将它upgrade的任务,发现工作量还挺大的。后来不经意看到一点关于xsl的东西,想到其实用xsl也可以完成将ExtJS标签化的任务,试着写了一下,结果发现只需一点点代码就实现了,并且几乎可以完全代替ExtFaces。

xsl实现十分轻量,只包含一个*.xsl文件和一个*.js文件,转换工作可以在后端用java来完成,也可以完全不依赖后端,在前端由浏览器完成。而ExtFaces却需要上百个java类,并且要深度介入jsf的api及配置文件,其前端js代码主要由后端的jsf组件渲染器用StringBuffer来完成,可维护性较差,升级困难。对比而言,我觉得这个比喻是恰当的:ExtFaces是出国旅游,xsl实现则是下楼散步。

xsl实现的限制是,因为它完全与后端无关,你需要用其他方式来实现对后端的调用,如Ext.Direct(不妨试一下DirectJNgine)。

像ExtFaces一样,xsl实现完全忠于ExtJS的api,使用它你只需要参考ExtJS的文档,除了以下几点额外的约定:
[list]
[*]如果标签的属性值是js表达式,请加一个@作为前缀,否则会被当前普通字面常量;
[*]额外的标签<ext:support base="res/ext-3.2.1"/>,用来引入ExtJS所需的资源,其中base属性为ExtJS文件所在路径;
[*]额外的标签<ext:listener event="click" handler="@onClick"/>,用来绑定事件监听器,监听器会添加到listeners集合中;
[*]额外的属性var,用来定义一个js的变量以便你可以在页面其他js代码中引用该组件实例;
[*]额外的属性rendered(JSF风格),rendered="false"则该组件不会被创建,一般要与后端的el表达式配合才有意义;
[*]额外的属性position(只应用于toolbar),用来控制toolbar在容器中的位置,而不是用容器的tbar或bbar属性。[/list]
试用:
下载并解压附件中的三个文件,然后双击其中的test.xhtml,如果你的默认浏览器是IE,可能它会提示你下载文件而不是打开它,这是因为系统的content type不对,可以修改注册表:
[HKEY_CLASSES_ROOT\.xhtml]
"Content Type"="text/xml"
你并不需要去下载ExtJS,这是因为
<ext:support base="http://www.extjs.com/deploy/dev"/>
当然,可能会有点慢。

页面代码如下,具体看里面的注解:

<?xml version="1.0" encoding="UTF-8"?>

<!-- 因为实际应用的是XML+XSLT的技术,页面文件必须符合XML格式 -->
<!-- 下面一行引入XSL样式表 -->
<?xml-stylesheet type="text/xsl" href="ext-builder.xsl"?>

<!-- 用xmlns声明标签前缀 -->
<!-- 可用的标签名称实际上就是ExtJS所有的xtype,可参考ExtJS api文档中Component的描述 -->
<!-- 可用的属性名称实际上就是该组件的config,具体参考ExtJS api文档,要注意的是,如果属性值是一个js表达式,请加一个@作为前缀 -->
<html xmlns:ext="http://bobbyyu/ext">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />

<!-- 下面一行引入ExtJS相关资源,base属性指向资源所在路径 -->
<ext:support base="http://www.extjs.com/deploy/dev"/>

<style>
body{padding:5px;}
</style>

<script type="text/javascript">
function onButtonClick() {
Ext.Msg.alert("Handler", "Event handled in a separate function.");
}
</script>
</head>
<body>
<h1>XSL + ExtJS</h1>
<br/>
<div id="div1">
<ext:panel var="panel1" title="Panel1" height="300" layout="border">
<!-- 用一个独立的函数处理事件 -->
<ext:button text="Button1" handler="@onButtonClick"/>

<!-- 也可以写一个in-line的函数来处理事件(注意里面不能加js的注释!) -->
<!-- 额外的listener标签用来绑定事件监听器,监听器会添加到listeners集合中 -->
<ext:button text="Button2">
<ext:listener event="click" handler="@function(b) {
Ext.Msg.alert('Handler', 'Event handled in a in-line function.');
}"/>
</ext:button>

<!-- 容器类组件可以包含普通Html内容 -->
<ext:form region="north" title="North Form" border="false">
<div style="padding:10px;background-color:#afa">
<h1>Html content...</h1>
</div>
</ext:form>

<ext:grid region="center" title="Center Grid" border="false">
<ext:arraystore var="ds1" data="@[
[1234, '张晓东', '人力资源部'],
[2345, '陈大山', '资讯科技部'],
[3456, '王同江', '公司业务部']
]">
<ext:datafield name="id"/>
<ext:datafield name="name"/>
<ext:datafield name="dept"/>
</ext:arraystore>
<ext:colmodel>
<ext:column header="员工编号"/>
<ext:column header="姓名"/>
<ext:column header="单位"/>
</ext:colmodel>
</ext:grid>

<!-- Toolbar与容器的关系用额外的position属性控制 -->
<ext:toolbar position="bottom">
<ext:button enableToggle="true" text="<b>Bold</b>"/>
<ext:button enableToggle="true" text="<i>Italic</i>"/>
<ext:button enableToggle="true" text="<u>Underline</u>"/>
<ext:tbseparator/>
<ext:button text="Fonts">
<ext:menu>
<ext:menuitem text="Tahoma"/>
<ext:menuitem text="Arial"/>
<ext:menuitem text="Verdana"/>
</ext:menu>
</ext:button>
</ext:toolbar>
</ext:panel>
</div>

<!-- 如果组件包含在一个普通Html元素内,它会自动renderTo该元素 -->
<div style="background:#f0f0f0;padding:5px;">
<ext:button text="Button rendered to a DIV" minWidth="80"/>
</div>
</body>
</html>

有关转换的实现原理有时间我另文描述。

因为是急就,测试不够,遇到问题麻烦大家反馈一下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值