简介
一个菜单有多个菜单项,一个列表有多个列表项,这是一类控件包含多个相同子项场景。这类控件有很多共有的特性,所以我们需要进行抽象和总结,来形成统一的功能和接口。根据子项的实现方式我们分为2种:
- 子项实现为子控件
- 子项仅作为控件的DOM片段
这2种实现方式的主要差别在于:
- 渲染DOM方面,
1) 子项实现为控件,渲染DOM的逻辑是独立的,不受父控件控制的
2) DOM片段,需要控件处理所有的子项的渲染逻辑
2. 状态改变和事件触发方面:
1) 子项实现为控件,状态的改变逻辑和事件触发由子控件处理,如果影响到其他的子控件,由父控件统一处理,例如选中一项时,父类会清理其他选中的子控件的选中状态。
2) DOM片段,的所有状态、事件触发都由包含这些DOM片段的控件来处理。
3. 选项的增删改方面
选项在增删改时,都需要在包含这些项的控件上做统一的处理。
4. 可复用性方面
1) 子项实现为控件,可以用于其他控件中,作为其他控件的子项,例如一个按钮分组包含多个按钮,一个工具栏也可以包括多个按钮。
2) 而DOM片段,只能在包含项的控件中实现,作为折中的方案,可以创建一个基类,其他控件实现这个基类即可。
5. 性能方面
1) 子项实现为控件,在生成的效率方面有很大的问题,控件的生成开销远远大于DOM片段的开销。
2) 事件处理方面,DOM片段可以用委托(delegate)的方式,统一处理子项的事件,可以不考虑子项的增删给控件带来的开销;子控件的方式必须自己触发事件,往上冒泡到父控件,统一处理
控件集合
一般的菜单、列表、tab、工具栏等控件的子项都是单独的子控件,我们可以抽取出一个扩展 ControlCollection 来实现子控件的共有的功能:
- 增删改
- 迭代,可以参考 .net 中 Enumerate的实现来提供接口
- 选中,在前面的文章中已经详细的介绍过选中
- 键盘处理
在实践中控件的嵌套需要处理一些问题:
- 子控件的默认配置,可以在父控件上统一配置子控件的默认选项,例如模板、选中状态使用的样式、出错显示的信息等等。
- 子控件之间的通信,有些子控件的状态改变会引起其他子控件的变化,例如单选,选中一个子控件时,需要清理其他子控件上的选中状态。
简单列表
我们把将子项实现为DOM片段的的控件的基类定义为简单列表,常用于需要显示大量数据的场景,例如 grid或者显示大量数据的list。我们需要在这种控件中实现:
- 数据源:所有的增删改、排序等数据操作,都通过数据源来处理,不直接操纵DOM片段
- 数据源绑定:理数据源加载、出错、增删改记录后,控件的DOM 随之变化
- 键盘事件处理
其实就是使用MVC的方式,把数据源和展示方式分离开来,所有选项的操作都是通过数据源的接口来实现。
Grid的操作最能体现出数据源操作数据的好处,查看示例