dojo dragon main logo

使用主题

部件的主题 key

Dojo 的主题框架使用“部件主题 key” 概念将重写的样式与对应部件的相关样式关联。覆盖的样式通常在主题中指定;但如果需要,也可以直接传给 theme 中间件的 classes 属性

一个部件的主题 key 的确切格式为:

{package-name}/{widget-css-module-name}

其中 package-name 是项目 package.jsonname 属性的值,widget-css-module-name 是部件使用的主 CSS 模块的文件名(不包括 .m.css 扩展名)。

主题 key 示例

给定如下项目:

package.json

{
    "name": "my-app"
}

遵循部件的 CSS 模块命名规范时,一个 src/widgets/MyWidget.ts 使用的 CSS 模块名类似于 src/styles/MyWidget.m.css。因此 MyWidget 的主题 key 为:

my-app/MyWidget

此处,部件的名称与其 CSS 模块文件的名称相同,但是开发人员要注意,不要将部件的主题 key 误认为就是部件的 TypeScript 类名。

再看第二个部件,没有遵循 CSS 模块的命名规范,如 src/widgets/BespokeWidget.ts 使用的 CSS 模块为 src/styles/BespokeStyleSheet.m.css,则部件的主题 key 应改为:

my-app/BespokeStyleSheet

编写主题

主题就是一个 TypeScript 模块,会导出一个默认对象,其中将部件主题 key 映射到导入的类型化的 CSS 模块上。主题中的 CSS 模块与部件直接使用的常规模块相同。一旦应用程序应用了主题,则主题定义对象中的主题 key 标识的每一个部件的样式,都会被主题 key 对应的 CSS 模块中的样式覆盖。

以下是 MyWidget 部件完整主题中的一个简单示例(使用默认的 CSS 模块 MyWidget.m.css),位于 my-app 项目中:

src/themes/myTheme/styles/MyWidget.m.css

.root {
    color: blue;
}

src/themes/myTheme/theme.ts

import * as myThemedWidgetCss from './styles/MyWidget.m.css';

export default {
    'my-app/MyWidget': myThemedWidgetCss
};

此处,MyWidget 遵循命名规范,将主样式类命名为 root,这样 myTheme 就可以被 src/themes/myTheme/styles/MyWidget.m.css CSS 模块中的 root 类覆盖掉。

通过主题 key my-app/MyWidget,主题将新的 root 样式类关联到 MyWidget 上。当应用 myTheme 主题后,MyWidget 会将其颜色设置为蓝色,且不会再接收其初始 CSS 模块的 root 类中定义的其他样式。

为第三方部件搭建主题

应用程序的主题可能需要包含第三方部件使用的样式,比如Dojo 自带部件库中提供的样式。

@dojo/cli-create-theme 中提供了一些工具,使用 dojo create theme CLI 命令,能为第三方部件快速生成主题脚手架。可通过以下方式在应用程序中安装:

npm install --save-dev @dojo/cli-create-theme

然后在项目根目录下按如下方式使用:

dojo create theme -n {myThemeName}

运行此命令,会在询问两个问题后开始创建 myThemeName 主题:

  • What Package to do you want to theme?
    • 答案应该是包含第三方部件的所有包,如 @dojo/widgets。本命令会继续询问更多的包,直到用户结束此操作。
  • Which of the {third-party-package} theme files would you like to scaffold?
    • 在回答第一个问题时,会显示第三方包中所有可主题化的部件。然后用户在其中选择一部分兼容的部件包含到输出的主题中,通常只选择在当前应用程序中实际用到的部件,确保主题足够小。

命令成功执行后,会在当前项目中创建几个文件:

  • src/themes/{myThemeName}/theme.ts
  • src/themes/{myThemeName}/{third-party-package}/path/to/{selectedWidget}.m.css

为所有 {selectedWidget} 创建的主题 CSS 模块都提供了可主题化的 CSS 选择器,然后就可以为 {myThemeName} 填充合适的样式规则。

兼容的包

任何包含 theme 目录的第三方包都是兼容的,其中既包含部件的 CSS 模块文件(*.m.css),也包含对应的编译后的定义文件(*.m.css.js - 详情参见分发主题)。

例如:

node_modules
└── {third-party-package}
    └── theme
        │   {widget}.m.css
        │   {widget}.m.css.js

分发主题

Dojo 的 cli-build-theme 提供了一个 CLI 命令,构建的主题可分发给多个应用程序使用。它会创建出以各种不同方式使用主题所需的所有文件

注意,当使用 dojo create theme 搭建新的主题时,并不需要使用 dojo build theme,因为所有相关文件都已就位。这主要用于使用 @dojo/cli-build-app@dojo/cli-build-widget 构建项目时来构建主题。

要使用此工具,在需要主题化的项目下安装 @dojo/cli-build-theme

npm install --save-dev @dojo/cli-build-theme

然后构建主题,请运行命令,并指定一个主题名以及一个可选的发布版本号:

dojo build theme --name={myThemeName} --release={releaseVersion}

如果没有指定 release,则会使用 package.json 中的当前版本号。

运行该命令后,会在项目中创建一个 dist/src/{myThemeName} 文件夹,其中包含:

使用 Dojo 提供的主题

@dojo/themes 包提供了一组立即可用的主题,涵盖了 Dojo 自带部件库的所有部件。可以按原样使用主题库,或者作为基础组合出完整的应用程序主题。

  1. 要使用主题,在项目中安装 @dojo/themes,比如使用 npm i @dojo/themes 命令。然后,对于常规的 Dojo 应用程序:

  2. 在项目的 main.css 文件中导入主题的 CSS 文件:

    @import '~@dojo/themes/dojo/index.css';
    
  3. 导入主题的 TypeScript 模块,然后使用:

    import theme from '@dojo/themes/dojo';
    
    render() {
        return w(Button, { theme }, [ 'Hello World' ]);
    }
    

如果尝试在 Custom elements 中使用它,则安装完 @dojo/themes 之后:

  1. index.html 中添加 Custom elements 专用的主题 CSS 文件:

    <link rel="stylesheet" href="node_modules/@dojo/themes/dojo/dojo-{version}.css" />
    
  2. index.html 中添加 Custom elements 专用的主题 JS 文件:

    <script src="node_modules/@dojo/themes/dojo/dojo-{version}.js"></script>