部件的基本原理

部件是所有 Dojo 应用程序的基本构建要素。部件是主要的封装单元,它能表示从用户界面的单个元素,到更高级别的容器元素(如 Form 表单、段落、页面甚至是完整的应用程序)等所有内容。

前言: 降低复杂度

单个部件通常表示应用程序中的单个职责。细微的职责自然会转化为单独的部件,而复杂的职责就需要拆分为几个相互依赖的部分。然后,每部分就可以实现为一个部件,其中一个或多个父容器部件会协调所有拆开部件的交互。在这种层级结构中,可以看出根部件在整体上实现了更大的责任,但实际上它是通过组合很多简单的部件实现的。

对一个完整的应用程序的来讲,它的所有需求集就是一个单一的、复杂的责任。使用 Dojo 实现这个完整的需求集,会产生具有层级结构的部件,通常从根节点的“Application”部件开始,然后根据每层功能分支出层层部件,最终到达表示 HTML 页面中单个元素的叶节点。

简单的好处

让部件尽可能简单的原因有:对单个部件而言,降低复杂度意味着更大的职责隔离(缩小范围);更容易做全面测试;减少出错的机会;更有针对性的修复错误;以及更广泛的组件复用潜力。

从整个应用程序的层面看,简单的部件使得我们更容易理解每个组件,以及它们是如何组合在一起的。

这些好处会简化日常维护,并最终降低了构建和运行应用程序的总开销。

基本的部件结构

部件的核心只是一个渲染函数,该函数返回虚拟 DOM 节点,正是通过虚拟 DOM 节点描述部件在网页中的结构。但是,应用程序通常需要处理更多逻辑,不仅仅是简单的罗列 HTML 元素,因此有意义的部件通常不仅仅由简单的渲染函数组成。

部件通常位于它们各自的、单独命名的 TypeScript 模块中,且每个模块默认导出定义的部件。

表示部件最简单的方法是基于普通函数,从渲染函数的工厂定义开始。Dojo 的 @dojo/framework/core/vdom 模块中提供了一个 create() 函数,允许作者定义他们自己的部件渲染函数工厂。可优先使用命名的渲染函数,因为这样有助于调试;但并非必须如此;部件也可以使用一个被导出的变量标识,该变量保存了部件的工厂定义。

对于更喜欢使用类的结构而不是函数的应用程序,Dojo 也提供了基于类的部件。此部件继承 @dojo/framework/core/WidgetBase 模块中提供的 WidgetBase,并必须要实现一个 render() 方法。

以下示例展示了一个 Dojo 应用程序的部件,虽然没有实际用途,但功能完整:

src/widgets/MyWidget.ts

基于函数的 Dojo 部件:

  1. import { create } from '@dojo/framework/core/vdom';
  2. const factory = create();
  3. export default factory(function MyWidget() {
  4. return [];
  5. });

基于类的 Dojo 部件:

  1. import WidgetBase from '@dojo/framework/core/WidgetBase';
  2. export default class MyWidget extends WidgetBase {
  3. protected render() {
  4. return [];
  5. }
  6. }

因为此部件的渲染函数返回的是空数组,所以在应用程序的输出中没有任何内容。部件通常返回一到多个虚拟 DOM 节点,以便在应用程序的 HTML 输出中包含有意义的结构。

将虚拟 DOM 节点转换为网页中的输出是由 Dojo 的渲染系统处理的。

部件样式

部件的 DOM 输出的样式是由 CSS 处理的,相关的样式类存在 CSS 模块文件中,它与部件的 TypeScript 模块是对应的。基于函数的部件和基于类的部件使用相同的样式。该主题会在样式和主题参考指南中详细介绍。