一直以来都想用jCT写出个WEB可视组件,本来打算从Grid入手做的,可是实际我做的时候发现如此的纠结
jCT本来就是模板技术,而组件可以认为是一种特定的模板技术(只不过模板被写道javascript代码里面了)
有想做组件这样的想法也不奇怪,因为模板所呈现的html原代码形式,改造扩充,调整结构,增加属性相对常规组件来说都是无比的方便。
可正是这种灵活性把jCT这个方向给毁了,因为,通用组件的模板代码完全体现不出来灵活性,而且还容易把事情搞复杂,
本来直接写html模板就已经很简单了,给个判断,加个循环,弄个分页都是很简单的事情
代码说话:注释用<!--注释-->
table部分
<!---///grid recorders-->
<!--grid 是子模板对象名,recorders是要传入的记录对象-->
<table>
<thead>
<!--表头部分,于其通过配置给出这些表头名不比多写几个th方便多少,这样你还可以增加自己的class等属性-->
<tr>
<th>用户名</th>
<th>实名</th>
<th>职位</th>
</tr>
</thead>
<tbody>
<!---this.Fn.V.push(this.rows.GetView(recorders));-->
<!--这个语句以前没有出现过,其实这就是jCT内部实现视图时push进输出数组的语句,
这里通过建立一个grid下的rows子模板,把循环独立出来,然后调用this.rows.GetView(recorders)并push进输出数组
来完成tbody主体,这样做的理由后面会阐述,注意recorders参数被直接给传过去了
-->
<!---///rows recorders-->
<!---for(var i=0;i<recorders.length;i++){var l=recorders[i];-->
<!--简单的循环输出了,这里面倒是可以写一段通用的代码,不过一样很大么?后面的阐述将否定他-->
<tr name="/" value="user.get" class="submitdblc">
<td name="id" value="+-l.id-+"><span name="user">+-l.user-+</span></td>
<!--注意id这个写的位置,这个是我应用里面的特殊需求,和上面的name="/"是配套的-->
<td name="xingming">+-l.xingming-+</td>
<td name="zhiwei">+-l.zhiwei-+</td>
</tr>
<!---}-->
<!---///rows-->
</tbody>
</table>
<div>
<!---this.Fn.V.push(page.GetView(toPages(recorders)));-->
<!--分页条控制输出,toPages是一个分页的函数,后面给出代码-->
</div>
<!---///grid-->
<!--下面是分页条控制的模板,由于这个几乎是通用的结构所以独立出来-->
<!---///page p-->
<div class="page">
<fieldset>
<!---for(var i=p.start;i<=p.end;i++){-->
<button class="pageButton" value="+-i-+">+-i-+</button>
<!---}-->
<button class="pageButton" value="+-p.prev-+">上9页</button>
<button class="pageButton" value="+-p.next-+">下9页</button>
<button class="pageButton" value="+-p.count-+">共+-p.count-+页+-p.rows-+条</button>
</fieldset>
</div>
<!---///page-->
分页的函数,在上面的代码里面要求后台返回的recorders对象里面直接含有相关参数,当然你可以把这些参数独立出来
/* *sets是分页所需要的信息,应该又后台输出的数据给出 * page_count总页数,这个后台没有给出的话也可以在js里计算,不过那就要提共每页有多少条记录了, * 我没有这样做,我习惯直接从后台计算出来,改造他当然不是什么大问题 * page_no当前显示的页 * rows_count记录总数 *range表示每次显示多少页的可选范围,我的习惯是9,因为个人喜好当前页优先处在中心位置这种形式 *当然这个函数也是这么写的,改造这个函数为常见的非中心分页的形式也很容易 *page返回值,有了这些值足以满足分页条的显示 * start:显示的开始页码 * end:显示的结束页码 * prev:前翻range页 * next:后翻range页 * no:当前页码 * rows:rows_count记录总数 */ function toPages (sets,range){ range=range||9; var rng=Math.floor(range/2); var page={start:0,end:0,prev:0,next:0}; page.count= sets.page_count|| 0; page.no = sets.page_no || 0; page.rows=sets.rows_count||0; if(!page.no) return page; page.start=page.no-rng; if(page.start<1) page.start=1; page.end=page.no+rng; if(page.end>page.count) page.end=page.count; page.prev=page.start-rng; if(page.prev<1) page.prev=1; page.next=page.end+rng; if(page.next>page.count) page.next=page.count; return page; }
那这里面有多少成分可以组件化!我想有这些方面吧,但问题和疑问同时存在
- 表头和recorders循环部分还是给出配置方便些
是的,对于简单的需求的确可以这样做,那有没有复杂的需求呢?
有,太普遍了,我们经常会遇到明明数据给的是int型,显示要用vchar型比如这个职位
就很可能是个id,显示确要用vchar,
呵呵,你说:后台给出的数据的时候用联合查询就OK了
没错,可以这样,不过当有更多的联合查询出现后,效率就不高了,其实这种情况多数时候是可以做成数据字典
在前台用js替换的,那我们是对数据进行前台前期预处理还是直接写到模板里呢?
我推崇直接写到模板里,为何这样!因为这只是一个特殊需求,相应的类似特殊需求也许会有一大堆,
也许替换数据字典后还需要保存原始的int值的比如职位模板部分可以这样写
看上去td有value这样的属性很古怪,但是这确实让整个结构和取值便的简单了,<td name="zhiwei" value="+-l.zhiwei-+">+-dict.zhiwei[l.zhiwei]-+</td>
如何取这个value我们就不谈了,这不并麻烦,但是如果你直接用jQuery的val方法的话,无疑是不行的
因为基于这种设计的val取值是有优先级的,也就是value属性优先,如果没有就取innerHTML了 - 排序,双击表头标题可以排序
的确这是个真正的需求,后续文章我会给出一个方案 - 编辑修改
其实不管是及时的双击弹出对话框修改还是cell直接修改,如果你使用jQuery这样的框架的话加一个class
然后写一段
就OK了这样的话上面保留职位的原始int值就凸显出意义了,那有读者说这不是也可以组件化么!$('table.dbleditbox tr').live('dblclick',yourfunc);
呵呵注意了:上面用的可是live呀,整个前台设置一个就可以生效了
其实也有例外,那就是有些dialog组件停止了event冒泡,可我认为这是dialog组件自身的问题, - 分页的请求需要传递给后台以及修改数据的提交
的确,如果仅仅看我上面的模板代码一些读者会一头雾水,这个咋提交请求!
我说这是模式问题,如果我们做一个组件就设计一种提交以及参数传递方法,那学习成本不是很高,代码重复不是很高!
看到这种写法了吧,用一个特殊的name="/"而他的value就是提交给后台的请求方法,至于参数的变更可以用统一的开发模式来设计定义,一个方法就满足这类需求<tr name="/" value="user.get" class="submitdblc">
但是这已经不属于组件设计问题了,这是开发模式问题,修改提交同样是这样
到此问题终于找到关键,组件VS设计模式,我们已知的组件确实是绑定了自己的设计模式,对开发者确实有不少限制,前台模板确实给了开发者自由,但同时也需要开发者摸索出自己的一条路,才能通行无阻。
jCT的 纠结 :对于复杂应用,开发者要有自己的设计模式才能"得道飞升”,因为复杂应用用组件的需求更大,是仔细的研究组件,还是从设计模式入手,写自己的代码,是个艰难的选择
可以确定的是 前台 模板+设计模式的代码量,灵活性都要远胜于纯组件,前台模板下应该是根据应用需求分类设计模板,形成制定的“组件”,自己及时书写的组件,不要忘记了jCT是编译型模板,最后的执行代码是可以独立保存成独立的js的(看来应该写一个这样的导出方法了),貌似分页条就可以独立成组件,如此小的组件,我咋都觉得还不如直接复制粘贴模板的方便