Dojo 样式进阶

认识Dojo中的界面控件:Dijit <br />Dojo框架区别于其他Ajax框架的一个显著特征就是它的界面控件系统:Dijit。Dijit是Dojo中界面控件的总称,他们使用灵活而且易于理解。每个Dijit控件都是由Dojo类以及控件中使用的图片,CSS等资源文件共同组成。通过Dijit架构,可以方便的创建灵活、可扩展、可定制外观的控件。下面将逐步介绍如何创建、配置Dijit控件,从而将其用在自己的web应用中。<br /><br /> 开始使用Dijit:引入需要的类和资源<br /> <br />前面提到Dijit的组成中除了Dojo类 阅读详情

Dojo 中的样式和主题

Dojo 部件最适合作为简单的组件,每个组件处理单一职责。它们应该尽可能的封装和模块化,以提高可重用性,同时避免与应用程序使用的其他组件出现冲突。

可以使用常规的 CSS 为部件设置样式,但是为了达到封装和复用的目标,每个部件应该维护各自的 CSS 模块(CSS module),该模块与部件的源代码存放在各自的文件中。这样就可以独立地设置各部件的样式,而不会与应用程序其他地方使用的类名冲突。

Dojo 界定出以下几类样式,每一类都代表了企业 web 应用程序中的样式需关注的不同方面和粒度:

如上述列表所示,无论是跨整个应用程序,还是单个样式类中的单条样式规则,Dojo 为应用程序开发者提供了几种互相补充的机制来提供或重写 CSS 样式类。

部件的结构样式

Dojo 借助 CSS Modules,既提供了 CSS 的所有灵活性,又引入了本地化样式类的额外优势,防止大型应用程序中无意间的样式冲突。Dojo 也为每个 CSS 模块生成类型定义文件,允许部件用与导入其他 TypeScript 模块相似的方式来导入 CSS 模块,并以类型安全的方式引用 CSS 类名,同时在设计期间可以使用 IDE 自动完成功能。

部件的 CSS 模块文件应该使用 .m.css 扩展名,并约定 CSS 模块的文件名要与关联的部件名保持一致。具有此扩展名的文件会被当作 CSS 模块来处理,而不是普通的 CSS 文件。

示例

以下是部件的 CSS 模块文件:

src/styles/MyWidget.m.css

.myWidgetClass {
	font-variant: small-caps;
}

.myWidgetExtraClass {
	font-style: italic;
}

在对应的部件中使用此样式,如下所示:

src/widgets/MyWidget.ts

import { create, tsx } from '@dojo/framework/core/vdom';

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

const factory = create();

export default factory(function MyWidget() {
	return <div classes={[css.myWidgetClass, css.myWidgetExtraClass]}>Hello from a Dojo widget!</div>;
});

在构建的应用程序中查看示例部件中的 CSS 类时,它们不会直接包含 myWidgetClass 和 myWidgetExtraClass,而是经过混淆处理的 CSS 类名,类似于 MyWidget-m__myWidgetClass__33zN8 和 MyWidget-m__myWidgetExtraClass___g3St。

混淆后的类名专用于 MyWidget 元素,而这是由 Dojo 的 CSS 模块化构建流程决定的。有了这种机制,则同一个应用程序的其他部件也可以使用 myWidgetClass 类名,即使具有不同的样式规则,也不会在每组样式间出现任何冲突。

警告: 混淆处理的 CSS 类名是不稳定的,可能会随着应用程序的构建而更改,所以开发人员不能显式地引用它们(例如试图在应用程序的其他位置定位一个元素)。

提取和扩展样式

CSS 自定义属性

Dojo 可以使用现代的 CSS 特性,例如自定义属性和 var(),来提取和集中管理应用程序中的通用样式属性。

不必在每个部件的 CSS 模块中为颜色或字体设置相同的值,而是通过提取自定义属性,在每个 CSS 模块中引用该属性名,然后在集中一处的 CSS :root 伪类中设置值。这种隔离更易于维护跨整个应用程序的公共样式。

例如:

src/themes/variables.css

:root {
	/* different sets of custom properties can be used if an application supports more than one possible theme */
	--light-background: lightgray;
	--light-foreground: black;

	--dark-background: black;
	--dark-foreground: lightgray;

	--padding: 32px;
}

src/themes/myDarkTheme/MyWidget.m.css

@import '../variables.css';

.root {
	margin: var(--padding);

	color: var(--dark-foreground);
	background: var(--dark-background);
}

注意,在一个页面中,:root 伪类是全局的,但是因为 Dojo 使用了 CSS 模块,则可能会在应用程序的多处指定 :root 属性。但是 Dojo 无法保证 CSS 模块的处理顺序,因此为了确保 :root 中属性的一致性,建议在应用程序的代码中只有一处 :root 定义,统一放在 variables.css 文件中。这个集中存放的变量文件是一个常规的 CSS 文件(不是一个 CSS 模块),当 CSS 模块需要使用自定义属性值时,可以使用 @import 导入。

Dojo 默认的构建流程按原样将自定义属性输出到应用程序的样式表中。对于最新的浏览器来说,这样做没有问题;但当使用的浏览器没有实现 CSS 自定义属性标准(如 IE)时,就会出现问题。为了解决这个问题,可以使用遗留模式(dojo build app --legacy)来构建应用程序,这种情况下,Dojo 会在构建期间解析自定义属性的值,并复制到输出的样式表中。一个值将包含原来的 var() 引用,第二个值是专为旧版浏览器解析的值,当无法处理 var() 时就使用解析后的值。

CSS 模块的组合功能

将主题应用到 Dojo 部件后,部件的默认样式类会完全被主题提供的样式类覆盖。当只需要通过主题修改样式类中的一部分属性,而其余属性依然使用默认值时,就会出现问题。

Dojo 应用程序中的 CSS 模块文件可以使用 composes: 功能将样式从一个类选择器应用到另一个类选择器。当通过调整现有的主题来创建一个新主题时,或者在单个主题中提取通用的样式属性时(注意,提取单个属性的值是更标准的做法是 CSS 自定义属性),这个功能是很有用的。

警告: composes: 功能可能会比较脆弱,例如当扩展一个不受当前应用程序控制的第三方主题时。第三方主题所做的任何更改,都可能会破坏基于 composes 功能的应用程序主题,且这样的破坏很难定位和解决。

但是,在大型应用程序中仔细使用此功能会很有用。比如,集中管理一组公共属性:

src/themes/common/ButtonBase.m.css

.buttonBase {
	margin-right: 10px;
	display: inline-block;
	font-size: 14px;
	text-align: left;
	background-color: white;
}

src/themes/myBlueTheme/MyButton.m.css

.root {
	composes: buttonBase from '../common/ButtonBase.m.css';
	background-color: blue;
}

Dojo 样式最佳实践

由于 Dojo 应用程序中的样式主要是针对单个部件的,因此不需要使用复杂的选择器。在 Dojo 中为应用程序设置样式时应尽可能简单,开发人员可通过以下几条简单的建议做到这一点:

  • 维护封装的部件样式
    • 一个 CSS 模块应只解决一个问题。与部件一一对应的 CSS 模块,通常只包含对应单个部件的样式类。CSS 模块也可以被多个部件共享,比如应用程序定义一个跨整个应用程序的、公共的排版模块。在 TypeScript 代码中,部件引用多个 CSS 模块也是一种常见的做法。
    • 不要在 CSS 模块之外使用样式类来引用部件,或者使用为部件提供覆盖样式的主题来引用部件。
    • 不要依赖构建的应用程序中的样式类名,因为 Dojo 会对类名做混淆处理。
  • Prefer class-level selector specificity
  • 优先使用类选择器(class selector)
    • 不应使用类型选择器(type selector),因为这样做会破坏部件的封装性,可能对使用相同元素类型的其他部件产生负面影响。
    • 不应使用 id 选择器(id selector)。Dojo 部件旨在封装和复用,而使用元素的 id 违背此目标。Dojo 提供了其他机制来增强或覆盖特定部件实例的样式,如部件的 classes 或 theme 属性。
  • 避免嵌套选择器
    • 部件应该足够简单,只使用一个类选择器。如果需要,部件也能使用多个、独立的类来应用额外的样式。单个部件也可以使用定义在多个 CSS 模块中的样式。
    • 复杂的部件应该被重构为一个简单的父部件和多个简单的子部件,这样可以为单独每个部件封装专用的样式。
  • 避免使用 BEM 命名规范
    • 优先使用与部件的用途相关的类名
  • 避免使用 !important

Dojo 应用程序支持主题

Dojo 应用程序需要一种方法,来为所有部件展示一致的外观,这样用户就可以整体地把握和使用应用程序功能,而不是认为将东拼西凑的元素混搭在网页中。这通常要根据公司或产品的营销主题来指定颜色、布局或字体等实现的。

制作支持主题的部件

考虑让部件支持主题需要做两方面的准备:

  1. 需要为部件的工厂函数注入 theme 中间件,const factory = create({ theme })
  2. 渲染部件时,应该使用 theme.classes(css) 返回的一个或多个部件样式类。

按惯例,当开发的部件需要分发时,还需要考虑第三点要求(Dojo 部件库中的部件都遵循此约定):

  1. 部件的 VDOM 根节点(即部件渲染后的最外围节点)应该包含一个名为 root 的样式类。这样当在自定义主题中覆写第三方可主题化部件的样式时,就能以一致的方式定位到顶层节点。

theme 中间件是从 @dojo/framework/core/middleware/theme 模块中导入的。

theme.classes 方法

theme.classes 将部件的 CSS 类名转换应用程序或部件的主题类名。

theme.classes<T extends ClassNames>(css: T): T;
  • 注意事项1: 主题的重写只在 CSS 类一级,而不是 CSS 类中的单个样式属性。
  • 注意事项2: 如果当前激活的主题没有重写给定的样式类,则部件会退而使用该类的默认样式属性。
  • 注意事项3: 如果当前激活的主题的确重写了给定的样式类,则 只会 将主题中指定的 CSS 属性应用到部件上。例如,如果部件的默认样式类包含 10 个 CSS 属性,但是当前的主题只指定了一个,则部件渲染时只会使用这一个 CSS 属性,并丢掉在主题中未重写的其他 9 个属性。

theme 中间件属性

可主题化部件示例

下面是一个可主题化部件的 CSS 模块文件:

src/styles/MyThemeableWidget.m.css

/* requirement 4, i.e. this widget is intended for wider distribution,
therefore its outer-most VDOM element uses the 'root' class: */
.root {
	font-family: sans-serif;
}

/* widgets can use any variety of ancillary CSS classes that are also themeable */
.myWidgetExtraThemeableClass {
	font-variant: small-caps;
}

/* extra 'fixed' classes can also be used to specify a widget's structural styling, which is not intended to be
overridden via a theme */
.myWidgetStructuralClass {
	font-style: italic;
}

在相应的可主题化的部件中使用这些样式:

src/widgets/MyThemeableWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import theme from '@dojo/framework/core/middleware/theme';

import * as css from '../styles/MyThemeableWidget.m.css';

/* requirement 1: */
const factory = create({ theme });

export default factory(function MyThemeableWidget({ middleware: { theme } }) {
	/* requirement 2 */
	const { root, myWidgetExtraThemeableClass } = theme.classes(css);
	return (
		<div
			classes={[
				/* requirement 3: */
				root,
				myWidgetExtraThemeableClass,
				css.myWidgetExtraThemeableClass
			]}
		>
			Hello from a themed Dojo widget!
		</div>
	);
});
使用多个 CSS 模块

部件也能导入和引用多个 CSS 模块,除了本指南的其它部分介绍的基于 CSS 的方法(CSS 自定义属性 和 CSS 模块化组合功能)之外,这提供了另一种通过 TypeScript 代码来提取和复用公共样式属性的方法。

扩展上述示例:

src/styles/MyThemeCommonStyles.m.css

.commonBase {
	border: 4px solid black;
	border-radius: 4em;
	padding: 2em;
}

src/widgets/MyThemeableWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import theme from '@dojo/framework/core/middleware/theme';

import * as css from '../styles/MyThemeableWidget.m.css';
import * as commonCss from '../styles/MyThemeCommonStyles.m.css';

const factory = create({ theme });

export default factory(function MyThemeableWidget({ middleware: { theme } }) {
	const { root } = theme.classes(css);
	const { commonBase } = theme.classes(commonCss);
	return <div classes={[root, commonBase, css.myWidgetExtraThemeableClass]}>Hello from a themed Dojo widget!</div>;
});

重写部件实例的主题

部件的使用者可以将一个有效的主题传给部件实例的 theme 属性,来重写特定部件实例的主题。当需要在应用程序的不同部分以多种方式显示给定的部件时,这个功能就能派上用场。

例如,在可主题化部件示例的基础上构建:

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

.root {
	color: blue;
}

src/themes/myThemeOverride/theme.ts

import * as myThemeableWidgetCss from './styles/MyThemeableWidget.m.css';

export default {
	'my-app/MyThemeableWidget': myThemeableWidgetCss
};

src/widgets/MyApp.tsx

import { create, tsx } from '@dojo/framework/core/vdom';

import MyThemeableWidget from './src/widgets/MyThemeableWidget.tsx';
import * as myThemeOverride from '../themes/myThemeOverride/theme.ts';

const factory = create();

export default factory(function MyApp() {
	return (
		<div>
			<MyThemeableWidget />
			<MyThemeableWidget theme={myThemeOverride} />
		</div>
	);
});

此处,渲染了两个 MyThemeableWidget 实例,如果指定了应用程序范围的主题,则第一个部件会使用此主题,否则使用部件的默认样式。相比之下,第二个部件始终使用 myThemeOverride 中定义的主题。

为部件传入额外的样式

主题机制提供了一种简便的方式,为应用程序中的每个部件统一应用自定义样式,但当用户希望为给定的部件实例应用额外的样式时,在这种场景下主题机制就不够灵活。

可以通过可主题化部件的 classes 属性来传入额外的样式类。这些样式类是追加的,不会重写部件已有的样式类,它们的目的是对已经存在的样式进行细粒度的调整。提供的每一组额外的样式类都需要按照两个级别的 key 进行分组:

  1. 合适的部件主题 key,用于指定应用样式类的部件,包括其中的任何子部件。
  2. 小部件使用的某个已存在的 CSS 类,部件使用者可以在单个 DOM 元素上扩展样式,一个部件上可扩展多个样式。

例如,额外的样式类属性的类型定义为:

type ExtraClassName = string | null | undefined | boolean;

interface Classes {
	[widgetThemeKey: string]: {
		[baseClassName: string]: ExtraClassName[];
	};
}

作为一个提供额外样式类的示例,下面调整 Dojo combobox 实例,以及其中的子部件 text input。此操作会将 combobox 使用的 text input 控件的背景色以及其自身面板的背景色改为蓝色。combobox 控件面板中的下拉箭头也会变为红色:

src/styles/MyComboBoxStyleTweaks.m.css

.blueBackground {
	background-color: blue;
}

.redArrow {
	color: red;
}

src/widgets/MyWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';

import ComboBox from '@dojo/widgets/combobox';
import * as myComboBoxStyleTweaks from '../styles/MyComboBoxStyleTweaks.m.css';

const myExtraClasses = {
	'@dojo/widgets/combobox': {
		controls: [myComboBoxStyleTweaks.blueBackground],
		trigger: [myComboBoxStyleTweaks.redArrow]
	},
	'@dojo/widgets/text-input': {
		input: [myComboBoxStyleTweaks.blueBackground]
	}
};

const factory = create();

export default factory(function MyWidget() {
	return (
		<div>
			Hello from a tweaked Dojo combobox!
			<ComboBox classes={myExtraClasses} results={['foo', 'bar']} />
		</div>
	);
});

注意,部件的作者负责显式地将 classes 属性传给所有的要使用样式类的子部件,因为 Dojo 本身无法将这个属性注入给或自动传给子部件。

制作支持主题的应用程序

要为应用程序中所有可主题化的部件指定一个主题,可在应用程序顶层部件中使用 theme 中间件中的 theme.set API。要设置默认的或初始的主题,则在调用 theme.set 之前要先使用 theme.get 进行确认。

例如,为应用程序设置一个初始主题:

src/App.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import theme from '@dojo/framework/core/middleware/theme';

import myTheme from '../themes/MyTheme/theme';

const factory = create({ theme });

export default factory(function App({ middleware: { theme }}) {
	// if the theme isn't set, set the default theme
	if (!theme.get()) {
		theme.set(myTheme);
	}
	return (
		// the application's widgets
	);
});

有关导入的 myTheme 结构说明,请参考编写主题。

请注意,使用可主题化的部件时,如果没有显示指定主题(例如,没有使用 theme.set 设置一个默认主题,也没有显式地重写部件实例的主题或样式类),则每个部件都使用默认的样式规则。

如果使用一个完全独立分发的主题(/learn/styling/working-with-themes#distributing-themes),应用程序还需要将囊括主题的 index.css 文件集成到自身的样式中来。在项目的 main.css 文件中导入。

src/main.css

@import '@{myThemePackageName}/{myThemeName}/index.css';

与之相比,另一种使用外部构建主题的部分内容的方法是通过主题组合功能(/learn/styling/working-with-themes#composing-off-dojo-themes)实现的。

更改当前激活的主题

theme 中间件中的 .set(theme) 函数用于在整个应用程序级别更改当前激活的主题。为 .set 传入所需的主题,这将让应用程序树中所有可主题化的部件失效,并使用新的主题重新渲染。

src/widgets/ThemeSwitcher.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import theme from '@dojo/framework/core/middleware/theme';

import myTheme from '../themes/MyTheme/theme';
import alternativeTheme from '../themes/MyAlternativeTheme/theme';

const factory = create({ theme });

export default factory(function ThemeSwitcher({ middleware: { theme } }) {
	return (
		<div>
			<button
				οnclick={() => {
					theme.set(myTheme);
				}}
			>
				Use Default Theme
			</button>
			<button
				οnclick={() => {
					theme.set(alternativeTheme);
				}}
			>
				Use Alternative Theme
			</button>
		</div>
	);
});

使用主题

部件的主题 key

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

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

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

其中 package-name 是项目 package.json 中 name 属性的值,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>
    

扩展 Dojo 主题

一旦在项目中安装了 @dojo/themes,就可将其作为扩展应用程序主题的基础,在新的主题中使用 CSS 模块化的组合功能来包含相关的组件。

@dojo/themes 中也包含一个 拥有 :root 的 variables.css 文件,如果扩展的应用程序主题需要在新主题的某处引用 Dojo 内置的属性,则可以导入该文件。

下面是一个 @dojo/widgets/button 使用新主题的示例,扩展自 @dojo/themes,将按钮的背景色改为绿色,而其他的主题样式属性保持不变:

src/themes/myTheme/theme.ts

import * as myButton from './myButton.m.css';

export default {
	'@dojo/widgets/button': myButton
};

src/themes/myTheme/myButton.m.css

@import '@dojo/themes/dojo/variables.css';

.root {
	composes: root from '@dojo/themes/dojo/button.m.css';
	background-color: var(--dojo-green);
}
Django+Vue前后端分离独立开发脚手架实战项目 除了模型字段映射,还可以添加计算字段或动态逻辑:允许通过方法返回任意计算结果,常用于统计信息、状态标签等衍生字段。此外,可在序列化器中定义局部和全局验证:raise serializers.ValidationError("标题长度不得小于5个字符")raise serializers.ValidationError("发布状态必须指定发布时间")这些验证函数在调用时自动触发,确保输入数据符合业务约束。除标准操作外,可通过@action装饰器添加额外端点:此时访问。 阅读详情

相关推荐

Jetty+Dojo+Tomcat的Comet配置

导入即可运行,包括下面jar。 jar包: cometd-api-0.9.20080221 cometd-bayeux-6.1.9 jetty-6.1.9 jetty-util-6.1.9 servlet-api-2.5-6.1.9 全网搜索dojox.cometd实现WEBQQ,没有可以运行的源码包项目,搞了五天,分享给大家,真实可用,jar包就找了好久,花了5分,搞了5天5分。共10分。 付原作者地址: http://blog.youkuaiyun.com/Garfier/article/details/5942826 感谢原作者!

6 大主流 Web 框架优缺点对比

我是否需要使用框架? 如果不尝试回答这个问题就是我们的失职,这越来越成为社会上某些人的口头禅,在网络平台上的争论也已经发展到犹如不需要额外编写 API 能更简单创建 Web 应用那样的地步。就像本系列中所有的内容一样,我们的回答也大都是依据这些内容。 虽然无框架也能正常工作,但是,这也是...

558

dojo-typescript-class:一个旨在使用 TypeScript 创建 Dojo 类的实验

道场打字稿类 这是一个旨在使用 TypeScript 创建 Dojo 类的实验。 不同的人已经进行了多次尝试。 这种尝试旨在使从 TypeScript 中创建 Dojo 类尽可能舒适,同时将奇怪的代码重复和陷阱降至最低。 魔法在dojoClass.js ,有关用法示例,请参阅MyTSDojoBaseClass.ts和MyTSDojoSubclass.ts 。 这个想法是使用普通的 TypeScript/ES6 语法创建类,然后将该原型对象传递给 Dojo 的declare()函数以创建 Dojo 类,然后将 Dojo 类中有趣的部分合并回 TypeScript 中。 运行单元测试 运行此代码的测试需要几个步骤。 运行npn install 转到并下载源 zip 并将其解压缩到 lib/ 目录下。 (您可能需要打开 test.html 并调整 requirejs 配置。) 运行npm

Eaglet 开源项目教程

Eaglet 开源项目教程 项目介绍 Eaglet 是一个高效、灵活的开源项目,旨在提供一个轻量级的框架,用于快速开发和部署应用程序。该项目由 Chung Chi300 发起,并在 GitHub 上开源,吸引了众多开发者的关注和贡献。 项目快速启动 环境准备 在开始之前,请确保您的开发环境已经安装了以下工具: Node.js (版本 >= 12.0.0) npm (版本 >= 6.0...

gitblog_00805的博客 518

Typescript官方手册

Typescript官方手册 完整版 从前打心眼儿里讨厌编译成JavaScript的这类语言,像Coffee,Dart等。 但是 在15年春节前后却爱上了TypeScript。 同时非常喜欢的框架Dojo,Angularjs也 宣布使用TypeScript做新版本的开发。 那么TypeScript究竟为何物?又有什么 魅力呢?

DOJO API 中文参考手册,附加注解实例(精心重新排版DOC文档)

Dojo 1.1.1 提供了上百个包,这些包分别放入三个一级命名空间:Dojo,Dijit和 DojoX 。其中 Dojo 是核心功能包 , Dijit 中存放的是 Dojo 所有的Widget 组件,而 DojoX 则是一些扩展或试验功能,DojoX 中的试验功能在成熟之后有可能在后续版本中移入到 Dojo 或 Dijit 命名空间中。列举了常用的一些包及其功能,以方便读者有个初步了解或供以后查阅

Dojo 样式简介

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

blocklang的博客 408

基于 HTML5 的 Dojo Widget 开发

简介: 当前的 Web 开发存在着两种趋势,一是基于 HTML、CSS 和 JavaScript 技术,比如以 Dojo 工具包、jQuery 等为基础的 HTML 页面;另一种是基于浏览器端运行时,如基于 Flash、Silverlight 等技术的 RIA 应用。前者占用的资源少,不需在浏览器上安装插件支持,后者界面更为美观,且便于实现一些较为复杂的展现功能。而且,因为 JavaScript 和 Flash 等平台之间的交互功能很受局限,基于这两类技术开发的页面内容很难做深度的集成。HTML5 作为新一代的 HTML 标准,不但对 JavaScript 的支持更加完善,同时还包含了丰富的绘图功能,这等同于兼具上面提到的两类技术的各自的优势。本文主要介绍基于 HTML5 来扩展 Dojo Widget,它不仅具有强大的 JavaScript 逻辑控制,而且具有丰富的页面展现和良好的运行性能。

dojo中datagrid中行高等样式设置

在dojo中使用控件datagrid,发现很多时候我们没办法在自己定义某些样式,显得很不随机。 以下是自己书写时总结的一些经验: 首先,对一般设置class属性后,想要起样式遵循当前应用,这是改变不大,只需要: .tundra .dojoxGrid,.tundra .dojoxGridS,.tundra .dojoxGridScrollbox{     background-col

xzchenxiao的专栏 2468

DOJO 基础学习

DOJO初学者学习代码,基于struts2上写的一些Dojo代码,主要是对一些数据的处理。。

dojo中文文档-dojo手册

dojo中文文档下载。dojo中文文档下载。

dojo 控件样式修改

require(["dojo"], function(dojo){ // Passing only an ID or node returns the computed style object of the node: dojo.style("thinger"); // Passing a node and a style property returns the c...

weixin_34092455的博客 352

将机器人urdf模型转换为Mujoco环境下的mjcf模型

在使用gym环境进行人形模型站立训练的过程中,我想要将之前ros环境下的机器人urdf模型导入到mujoco环境下,这时候就需要将urdf模型转换为mujoco专用的mjcf模型。-AzureLoong.urdf是机器人模型(我这里使用青龙的模型);--custom_robot.xml是转换完成之后的机器人模型的名字和格式;包要求 Python 版本必须是 3.11 或更高),保证自己的其他训练环境和依赖不被干扰。首先将meshes文件迁移到需要输出的目录下,然后再运行转换命令。最后就可以成功输出了。

weixin_44334573的博客 3756

Dojo 部件进阶

翻译自:https://github.com/dojo/framework/blob/master/docs/en/creating-widgets/supplemental.md 部件的基本原理 部件是所有 Dojo 应用程序的基本构建要素。部件是主要的封装单元,它能表示从用户界面的单个元素,到更高级别的容器元素(如 Form 表单、段落、页面甚至是完整的应用程序)等所有内容。 前言: 降低复杂...

caisao7252的博客 215

ldpc编解码器设计与仿真

计算校验节点到变量节点的消息 m_{c \to v}=2 \cdot atanh(\prod_{v’ \in N©\setminus v}tanh(\frac{m_{v’ \to c}}{2}))。计算变量节点到校验节点的消息 m_{v \to c}=L_{v,0}+\sum_{c’ \in M(v)\setminus c}m_{c’ \to v}。◦ 对于每个变量节点 v,计算最终 LLR 值 L_{v,f}=L_{v,0}+\sum_{c \in M(v)}m_{c \to v}。

youngerwang的博客 809

”COMSOL“竟然如此简单!我悟了!!

COMSOL Multiphysics具有强大的多物理场全耦合仿真分析功能、高效的计算性能,可以保证数值仿真的高度精确,已被广泛应用于各个学科领域,近年来运用COMSOL来解决电化学实际工程问题也越来越普遍。

C1012562281的博客 3448

用dojo实现动态更换样式

以下几个例子,个人觉得很有用,希望能看见的你们也能有用: dojo.require("dojo.lang.common"); dojo.require("dojo.event.common"); dojo.require("dojo.html.style"); dojo.require("dojo.string.extras"); dojo.require("dojo.c

xzchenxiao的专栏 6087

HC32F460的GPIO重映射实战:如何用3步搞定SPI引脚冲突问题

本文详细介绍了HC32F460的GPIO重映射功能,通过三步操作解决SPI引脚冲突问题。文章解析了HC32F460的FuncGroup功能分组机制,提供了具体的寄存器配置步骤和验证技巧,并对比了与传统方案的性能优势,帮助工程师灵活配置引脚,优化硬件设计。

t4y5u6i7o的博客 918

Dojo 进阶

官网 https://dojo.io 序言 - 构建企业级 web 应用程序 在热衷敏捷交付的时代,鼓励将小功能点持续地交付给用户。软件行业开始青睐这种方式,因为它最大限度地降低风险,并最大限度地提高用户的参与度和满意度。 即使采用现代的交付方式,一些风险仍然不可避免。复杂性就是这样一种风险,对于成熟的应用程序而言,复杂性更成为一个重要的关注点。无论应用程序遵循什么样的系统架构,随着时间的推移,许...

blocklang的博客 344

金蝶K3系统物料主数据后台表对应字段一览

我们说到物料表,一般是指t_icitem,但正确的说t_icitem并不是一张有,而是一张视图,不过我们对于数据库物料表中的大部分操作,都是通过此视图来完成。比如经常通过此视图,来成批修改数量,单价精度,是否启用批次等一些字段,有的时候,对于账套已经启用,并且已经有业务发生的物料,有一些关键属性也需要通过修改物料表t_icitem来进行。 当然修改的时候,需要考虑一些前提条件的。 比如说我有一个客户新建的账套,在月底结账时发现,要改一种成本核算方法,启用时用的是加权平法,现在想改成移动平均法,这样的情况,

hzfw2008的博客 1万+

基于Python的房地产评估数据抓取与分析 —— 房价走势与市场报告

在房地产行业中,了解和分析房产价格的变化趋势、各个地区的房价差异以及市场评价报告,可以帮助投资者、购房者以及政策制定者做出更加明智的决策。本文介绍了如何使用Python爬虫技术抓取房地产平台上的房产评估报告、价格走势等数据,并对抓取的数据进行分析。通过这些技术,您可以自动化抓取房地产平台的数据,分析房价走势,获取市场报告,为房地产投资决策提供数据支持。假设我们要从链家网抓取某个房产的价格、房产描述以及历史成交价格,首先需要获取目标房产页面的URL,并发送HTTP请求。伪装为常见浏览器,避免被识别为爬虫。

2201_76125261的博客 847

dojo之Button篇

1、设计关键 (1)设置Button背景图片 (2)设计Button点击事件 2、设计步骤 (1)设置Button背景图片       A、样式设置 .btnIcon{ width:30px; height:32px; background:url("../images/search.png") cente

游海东的技术专栏 2333

A.特定领域知识图谱知识推理方案:知识图谱推理算法综述[五]-GeniePath会自动过滤多度“邻居“的图神经网络算法。

构图对于GNN格外重要。那么怎样构图才有信息、有意义呢?如果节点的邻居只有自己,即邻接矩阵为对角阵时,GNN会退化成一个DNN模型。图中每个节点都是孤立的,相当图信息并不能相比其他方法带来增益。如果图特别稠密,比如是一个clique,即每个节点都和所有其他节点有边连接。同样的,这样的图信息同样是信息熵为0。经验上讲,节点度分布有区分度的图是相对有价值的。查看图的节点度分布。比如二类分类,分析正负例的图拓扑当然,构图和实际场景强相关。

丨汀、的博客 437
上一篇: Dojo 样式简介
下一篇: Dojo 国际化简介
blocklang
博客等级 码龄7年 2粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值