最近的项目里很多地方用了全选框。用一个checkbox来控制一组checkbox(后面就用group指代吧)的全选和全不选。
老实说,我并不喜欢全选框的设计。Checkbox是选择用的,其语义就在于选与不选。全选框干了些什么?选中时则选择group所有,未选中时则group全不选。也就是说,全选框的状态对应group中所有checkbox的状态。那么,如果要做得够好的话,group中的checkbox状态变化时,全选框的状态也应该同步变化。但这就有一个地方暧昧了——group中checkbox只有部分选中时,全选框该是什么状态?
对很多人来说,这个问题不是问题,规定一下就可以了——group部分选中时,全选框选中或不选中都可以,只要在同一个项目/库中一致就可以了。这样看来,这个问题就规避掉了。不过新的问题会接着产生,例如:若group中成员可以增加减少,那么新增成员的状态,全选框的状态如何“规定”。这儿的问题就很多了,为了让一切能够行得通,势必增加大量的细节定义。否则,就会产生太多的不明确行为。而大量的细节定义,又会让实现者容易产生混乱。就算最后能够正确的“完美”实现,也实在是“杀鸡用牛刀”的典范。而且,过多不直观的定义,基本可以认定,下一次的使用又会发生变化,也就是说,没有重用的价值。
那么问题的根源在哪儿呢?难道这个问题真有这么高的复杂度?
显然不是。我们要的是全选、全不选。而实际上,checkbox不适合做这个工作。由于checkbox自身带有(带状态的)语义,为了配合这些语义,问题变复杂了。我们只是需要选择,并不需要选择触发器本身的状态。只要换一个没有状态的选择触发器就可以了,例如,一个按钮,一个标签。这样的好处很明显,你可以给一个按钮/标签任何语义,例如全选和全不选,如果你高兴多点快捷操作,还可以指定选中某种状态。而且由于触发器没有状态,就没有跟踪选择对象状态的必要。这儿倒不是说跟踪状态本身不好,只不过大多数情况下,实际上没有这个需求。而一旦选择checkbox,语义上默认就需要跟踪状态。而用无状态的触发器的实例是有的,例如GMail。(我大概只能举这个例子了,因为没有搜集过这方面的资料,而且,毕竟,我不是做UI的。)
或许,有这样一篇文章,极大原因在于自己对于别人的全选框的实现很不爽。下面附上最近看了jQuery后的全选框的实现。项目中的比这复杂,因为没用任何框架。
/*
* This function is to implement a checkbox group controled by a checkbox.
* It doesn't change other behaviors in those elements.
* This function is depended on jquery.
* @param: allSelector {jquery selector} it is nothing special, though all-box should be one and possible an id.
* boxesSelector {jquery selector} expect it as a string, don't try other selectors.
* It should be like "input[type=checkbox][name=boxg1]".
* Now I doesn't plan to deal with more complex selector.
* mode {Boolean} if it's true, all-box will be checked when any in the checkbox group is checked.
*/
function CheckboxGroup(allSelector, boxesSelector, mode) {
$(allSelector).bind('click',function(e){
$(boxesSelector).attr("checked",$(allSelector).attr("checked"));
});
$(boxesSelector).bind('click',function(e){
var num = $(boxesSelector).length;
var cnt = $(boxesSelector+"[checked=true]").length;
/*
* The all-box will be checked when all checkboxes in group are checked(cnt == num),
* or some checkboxes are checked if mode is true(mode && cnt > 0).
*/
$(allSelector).attr("checked",((cnt == num) || (mode && cnt > 0)));
});
}
没有评论:
发表评论