介绍

Dojo 是基于 HTML 的技术,使用 CSS 为框架中的元素和用它开发的应用程序设置样式。

Dojo 鼓励将结构样式封装在各部件中,以便最大限度复用;同时将外观主题设置到应用程序所有部件上。用户为他们的应用程序设置样式和主题时,这种模式提供了固定的套路,即使混合使用 Dojo 的 @dojo/widgets中的部件、由第三方提供的部件或者为特定应用程序开发的内部使用的部件时也是如此。

功能描述
为单个部件设置样式CSS Modules 用于定义,在单个部件的作用域内有效的样式,避免潜在的交叉污染和样式冲突。通过类型化的 CSS 模块导入和 IDE 自动完成功能,部件可以精确的引用 CSS 类名。
强大的主题支持可以轻松开发出支持主题的部件,这样的部件既能使用简化的、中心化的应用程序主题,也能调整或覆盖单个实例的目标样式(如果需要的话)。CLI 工具支持分发自定义主题。
响应式的主题变更与 Dojo 应用程序中的其他响应式状态变更类似,当一个部件或者整个应用程序的主题发生变化时,只有受影响的部件才会重新渲染。
CSS 属性CSS 模块能使用 CSS 自定义属性和 var() 来设置主题变体的属性和颜色。
简化定义第三方部件的主题应用程序可以轻松扩展主题以覆盖第三方部件,如 Dojo 内置部件库中的部件,Dojo 也提供了开箱即用的主题,应用程序可直接使用。CLI 工具极大简化了主题的创建和组合。

基本用法

注意: 以下示例是按顺序在前一个示例的基础上构建的。每个示例都尽量简短,只突出显示跟上一个示例相比发生变化的部分。

这些示例假定应用程序名为:

package.json

  1. {
  2. "name": "my-app"
  3. }

应用程序名与部件主题的 key 有关。

为单个部件设置样式

  • 为每个部件单独定义一个 CSS 模块
  • 在部件的 TypeScript 代码中使用相应的类型化的样式类

src/styles/MyWidget.m.css

  1. .root {
  2. font-family: sans-serif;
  3. }

src/widgets/MyWidget.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import * as css from '../styles/MyWidget.m.css';
  3. const factory = create();
  4. export default factory(function MyWidget() {
  5. return <div classes={[css.root]}>My Widget</div>;
  6. });

让部件支持主题

src/widgets/MyWidget.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import theme from '@dojo/framework/core/middleware/theme';
  3. import * as css from '../styles/MyWidget.m.css';
  4. const factory = create({ theme });
  5. export default factory(function MyWidget({ middleware: { theme } }) {
  6. const { root } = theme.classes(css);
  7. return <div classes={[root]}>My Widget</div>;
  8. });

在部件中应用主题变体

  • 在部件的 root 上设置 theme.variant 样式。
  • 将 css 属性应用到正确的 DOM 层级上,并且不能暴露出部件的 DOM。

src/widgets/MyWidget.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import theme from '@dojo/framework/core/middleware/theme';
  3. import * as css from '../styles/MyWidget.m.css';
  4. const factory = create({ theme });
  5. export default factory(function MyWidget({ middleware: { theme } }) {
  6. const { root } = theme.classes(css);
  7. const variantRoot = theme.variant();
  8. return <div classes={[root, variantRoot]}>My Widget</div>;
  9. });

创建主题

  • 使用自定义的主题样式属性重写部件默认的 CSS 类
  • 通过合适的部件主题 key 将一个或多个重写后的样式链接到主题结构中

src/themes/MyTheme/MyWidget.m.css

  1. .root {
  2. color: hotpink;
  3. background-color: slategray;
  4. }

src/themes/MyTheme/theme.ts

  1. import * as myWidgetCss from './MyWidget.m.css';
  2. export default {
  3. 'my-app/MyWidget': myWidgetCss
  4. };

创建主题的变体

  • 将主题变量作为 CSS 自定义属性存放在 variant 模块中
  • 通过 var() 引用自定义属性
  • 不依赖于本地变量或者公共的 variables.css 文件

src/themes/variants/default.m.css

  1. /* single root class */
  2. :root {
  3. --foreground: hotpink;
  4. --background: slategray;
  5. }

src/themes/MyTheme/MyWidget.m.css

  1. .root {
  2. color: var(--foreground);
  3. background-color: var(--background);
  4. }

src/themes/MyTheme/index.tsx

  1. import * as defaultVariant from './variants/default.m.css';
  2. import * as myWidgetCss from './MyWidget.m.css';
  3. export default {
  4. theme: {
  5. 'my-app/MyWidget': myWidgetCss
  6. },
  7. variants: {
  8. default: defaultVariant
  9. }
  10. };

指定默认的应用程序主题

theme 中间件可用于设置应用程序主题。要设置“默认的”或初始化主题,则使用 theme.set 函数,同时用 theme.get 函数确定是否需要设置主题。应该在应用程序的顶级部件中设置默认主题。

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import theme from '@dojo/framework/core/middleware/theme';
  3. import myTheme from '../themes/MyTheme/theme';
  4. const factory = create({ theme });
  5. export default factory(function App({ middleware: { theme }}) {
  6. // if the theme isn't set, set the default theme
  7. if (!theme.get()) {
  8. theme.set(myTheme);
  9. }
  10. return (
  11. // the application's widgets
  12. );
  13. });

注意: 当同时使用基于函数的部件和基于类的部件时,应该使用应用程序注册器来注册主题。当使用基于类的部件时(如 @dojo/widgets) 也是如此。详情参考基于类部件的主题

设置主题变体

如果将主题与 variants 一起使用,则自动选用 default 变体。使用 theme.set 函数来设置不同的变体——传入的变体名必须是主题导出的 variants 的 key 值。

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import theme from '@dojo/framework/core/middleware/theme';
  3. import myTheme from '../themes/MyTheme/theme';
  4. const factory = create({ theme });
  5. export default factory(function App({ middleware: { theme }}) {
  6. // if the theme isn't set, set the default theme
  7. if (!theme.get()) {
  8. theme.set(myTheme, 'variant-name');
  9. }
  10. return (
  11. // the application's widgets
  12. );
  13. });

更改应用程序主题

src/widgets/ThemeSwitcher.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import theme from '@dojo/framework/core/middleware/theme';
  3. import myTheme from '../themes/MyTheme/theme';
  4. import alternativeTheme from '../themes/MyAlternativeTheme/theme';
  5. const factory = create({ theme });
  6. export default factory(function ThemeSwitcher({ middleware: { theme } }) {
  7. return (
  8. <div>
  9. <button
  10. onclick={() => {
  11. theme.set(myTheme);
  12. }}
  13. >
  14. Use Default Theme
  15. </button>
  16. <button
  17. onclick={() => {
  18. theme.set(alternativeTheme);
  19. }}
  20. >
  21. Use Alternative Theme
  22. </button>
  23. </div>
  24. );
  25. });