CSS-in-TS
StyleSheet maker 函数可以使用特殊类型描述生成的样式,因此在使用它们时,TypeScript 会提示可用的 CSS 选择器。此功能利用了 TypeScript 泛型,将样式的实现隐藏在外部接口之后。
风格描述
使用 EffCSS 开发样式的第一步是将提供的功能捕获为 TypeScript 类型。自 v4.6.0 版本起,对象的嵌套层级不再有限制,并且可以在任何层级定义字符串或数值类型的属性。
对于所有级别,建议使用以 lowerCamelCase 格式编写的有意义的名称。
export type TCustomMaker = {
/**
* Width utility
*/
w: 's' | 'm' | 'l';
/**
* Logo
*/
logo: {
/**
* Spin animation
*/
spin: '';
/**
* Logo scale
*/
scale: 1 | 2;
};
/**
* Body
*/
body: {
/**
* Padding size
*/
p: 's' | 'm' | 'l';
};
/**
* Footer
*/
footer: {
/**
* Is footer hidden
*/
hidden: '';
};
/**
* Panel block
*/
panel: {
/**
* Is panel modal
*/
modal: '';
/**
* Max panel width
*/
max: 'vw' | 'parent';
/**
* Close button
*/
closeBtn: Record<string, never>;
}
};样式实现
使用 EffCSS 开发样式的第二步是在 StyleSheet maker 函数框架内实现所述功能。为了在 EffCSS 中生成带有样式表前缀的唯一选择器,需要使用 select 工具。该工具还会检查已实现的 CSS 选择器的有效性。
每个选择器都是通过路径点连接到所需的属性,并在其值(如果不是对象)前添加冒号 : 来形成的:
import { TStyleSheetMaker } from 'effcss';
export type TCustomMaker = {...};
const maker: TStyleSheetMaker = ({
select,
}) => {
const selector = select<TCustomMaker>;
return {
[selector('logo')]: {
// ...
},
[selector('logo.scale:1')]: {
// ...
},
[selector('logo.spin:')]: {
// ...
},
[selector('panel.closeBtn')]: {
// ...
}
}
};
export default maker;样式的使用
要获取选择器解析器,需要将相应的 StyleSheet maker 函数传递给 Style provider 对象的 use 方法。解析器有两个方法:list 和 obj,它们用于输出带有必要选择器的 HTML 属性。
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (use: IStyleProvider['use']) => {
const [css] = use(customStyle);
return {
firstElemAttrs: css.obj<TCustomMaker>({
w: 's',
panel: {
max: 'parent'
}
}), // {[attributeName]: 'selectors_string'}
secondElemAttrs: css.list<TCustomMaker>('logo.spin:', 'body.p:m') // {[attributeName]: 'selectors_string'}
};
};属性生成模式
Style provider 组件可以通过 2 个属性影响选择器的生成:
mode可以取值a(使用data-*属性)和c(使用class属性),min是一个布尔属性,允许您压缩 BEM 选择器。
CSS 类生成更具可预测性,而数据属性生成则允许你在视觉上区分不同的样式表。选择你最喜欢的方式即可。
代码压缩会在选择器中保留唯一的前缀,因此不同表格的样式将保持隔离,同时选择器的长度将显著减少。
如果使用 a 生成模式,并且所使用的框架支持此语法,则生成的属性可以直接传递给布局:
<div {...firstElemAttrs}>...</div>如果使用 c 生成模式,您可以从对象中获取类并将其传递给布局:
<div className={firstElemAttrs.class}>...</div>显式生成类名
从 4.10.0 版本开始,您可以使用 cx 工具直接获取所需的 CSS 类选择器。此工具会忽略 Style provider 的 mode 属性,并返回一个包含类名的字符串:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
return {
firstElemAttrs: provider.cx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
}),
secondElemAttrs: provider.cx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m'])
};
};显式生成数据属性
从 4.10.0 版本开始,您可以使用 dx 工具直接获取所需的 CSS 数据属性选择器。此工具会忽略 Style provider 的 mode 属性,并返回一个包含数据属性的对象:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
return {
firstElemAttrs: provider.dx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
}),
secondElemAttrs: provider.dx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m'])
};
};WARNING
每个 StyleSheet maker 只创建一个样式表,因此您需要将 cx 或 dx 实用程序与一个 StyleSheet maker 一起使用,但不能同时使用两个实用程序。
益处
所描述的方法可以将契约与实现分离。在开发过程中,您一开始就知道应该提供哪些 CSS 选择器,任何第三方开发人员都可以导入您的 TCustomMaker 类型并获取所需的样式,而无需查看您的 StyleSheet maker 函数。考虑到 JS 文件通常会在编译过程中被压缩,这种方法可以节省大量时间。
此外,EffCSS 会为每个样式表生成自己独特的样式选择器,从而消除了重新定义样式选择器的风险。
因此,EffCSS 允许您超越通常的 CSS 创建,接近 CSS-in-TS 的角色。