使用 Tailwind CSS 编写组件变体的不同方法

使用 tailwind css 编写组件变体的不同方法

问题

传统上,当使用 tailwind css 编写组件变体时,我会使用简单的类映射将 prop 值映射到组件插槽:

type ttheme = "default" | "secondary";interface icomponentslot {  root: string;  accent: string;}const theme_map: record = {  default: {    root: "bg-red hover:background-pink",    accent: "text-blue hover:text-green",  },  secondary: {    root: "bg-green hover:background-black",    accent: "text-pink hover:text-white",  }}
/**/

登录后复制

这种方法的问题是保持所需的类相互一致,确保每个变体都具有所有必需的类,特别是在更复杂的组件中。在我们想要跨不同组件插槽共享样式(例如文本颜色)的组件中,需要我们单独更新每个插槽。

tailwind 的局限性

tailwind 通过扫描代码库和匹配字符串来生成实用程序类,这意味着虽然 tailwind 可以从任意值创建类,但我们无法在不创建安全列表的情况下动态启动它们。所以这行不通:

// .tstype ttheme = "default" | "secondary";const colors: record = {  default: "red",  secondary: "blue",}// .html

登录后复制

但是,我们可以通过利用 css 变量来模仿所需的行为,这是 tailwind 在其许多类的底层使用的东西。我们可以使用以下语法通过 tailwind 中的类设置变量: [–my-variable-key:–my-variable-value]
那么我们如何更新上面的代码示例以使用动态值?

// .tstype ttheme = "default" | "secondary";const colors: record = {  default: "[--text-color:red]",  secondary: "[--text-color:blue]",}// .html

登录后复制

解决最初的问题

现在我们了解了 tailwind 的局限性,我们需要研究解决由类映射方法引起的初始问题的方法。我们可以从简化我们的类映射开始:

type ttheme = "default" | "secondary";interface icomponentslot {  root: string;  accent: string;}const theme_map: record = {  default: "[--backgound:red] [--hover__background:pink] [--text:blue] [--hover__text:green]",  secondary: "[--backgound:green] [--hover__background:black] [--text:pink] [--hover__text:white]",}
/**/

登录后复制

不幸的是,仅此并不能解决我们的问题,我们仍然无法确保我们已经设置了正确显示每个变体所需的所有类。那么我们如何才能更进一步呢?好吧,我们可以开始编写一个接口来强制我们设置指定的值:

interface icomponentthemevariables {  backgound: string;  hover__backgound: string;  text: string;  hover__text: string;}const theme_map: record = {  default: {    backgound: "[--backgound:red]",    text: "[--hover__background:pink]",    hover__background: "[--text:blue]",    hover__text:"[--hover__text:green]",  },  secondary: {    backgound: "[--backgound:green]",    text: "[--hover__background:black]",    hover__background: "[--text:pink]",    hover__text:"[--hover__text:white]",  },}

登录后复制

所以这可行,但是,仍然有一个问题,没有什么可以阻止我们混合字符串值。例如,我们可能不小心将关键背景设置为 [–text:blue]。

所以也许我们也应该输入我们的值。我们无法输入整个类,这将是维护的噩梦,那么如果我们输入颜色并编写一个辅助方法来生成 css 变量会怎么样:

type tcolor = "red" | "pink" | "blue" | "green" | "black" | "white";interface icomponentthemevariables {  backgound: tcolor;  hover__backgound: tcolor;  text: tcolor;  hover__text: tcolor;}// example variablemap method at the end of the articleconst theme_map: record = {  default: variablemap({    backgound: "red",    text: "pink",    hover__background: "blue",    hover__text:"green",  }),  secondary: variablemap({    backgound: "green",    text: "black",    hover__background: "pink",    hover__text:"white",  }),}

登录后复制

好的,这太棒了,我们可以确保始终为组件的每个变体设置正确的变量。但是等等,我们刚刚遇到了 tailwind 发现的最初问题,我们不能只生成类,tailwind 不会选择它们。那么我们该如何解决这个问题呢?

js 中的 css 怎么样?

js 中的 css 似乎是显而易见的答案,只需生成一个类,该类创建具有正确变量的自定义类。但有一个障碍,javascript 在客户端上运行,这会导致“flash”,组件最初加载时没有设置变量,然后更新才能正确显示。

立即学习“前端免费学习笔记(深入)”;

js 库中的 css 如何处理这个问题?

像 emotion 这样的库通过插入有关组件的内联样式标签来处理这个问题:

  
.css-21cs4 { font-size: 12 }
text

登录后复制

这对我来说不是正确的方法。

那么我们如何解决这个问题呢?

我正在使用 vue,这让我走上了 css 中 v-bind 的道路,这是 vue 中将 javascript 绑定为 css 值的功能。过去我只很少使用这个功能,并且从未深入研究过它的用途。 css 中的 v-bind 只是在相关元素上设置内联样式。

这让我想起了几个月前我从 tailwind css 的创建者 adam wathan 那里看到的一条推文:

那么这对我们有什么帮助呢?好吧,虽然我们无法动态生成 tailwind 类,但我们可以动态生成内联样式并使用 tailwind 类中的这些内联样式。那会是什么样子?

type tcolor = "red" | "pink" | "blue" | "green" | "black" | "white";interface icomponentthemevariables {  backgound: tcolor;  hover__backgound: tcolor;  text: tcolor;  hover__text: tcolor;}// example variablemap method at the end of the articleconst theme_map: record = {  default: variablemap({    backgound: "red",    text: "pink",    hover__background: "blue",    hover__text: "green",  }),  secondary: variablemap({    backgound: "green",    text: "black",    hover__background: "pink",    hover__text: "white",  }),}
/**/
/*output:
...
*/

登录后复制

结论

通过结合 typescript、css 变量和内联样式的功能,我们能够确保在使用 tailwind css 时,我们组件的每个变体都会设置每个选项并具有正确的类型。

这是一种实验性方法,我相信会有一些强烈的意见。我确信这是最好的方法吗?现阶段,我不确定,但我认为它有腿。

如果您觉得这篇文章有趣或有用,请在 bluesky(我在这里最活跃)、medium、dev 和/或 twitter 上关注我。

示例:变量映射

// variableMap exampleexport const variableMap = <T extends Record>(  map: T): string => {  const styles: string[] = [];  Object.entries(map).forEach(([key, value]) => {    const wrappedValue = value.startsWith("--") ? `var(${value})` : value;    const variableClass = `--${key}: ${wrappedValue};`;    styles.push(variableClass);  });  return styles.join(" ");};

登录后复制

以上就是使用 Tailwind CSS 编写组件变体的不同方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2649918.html

(0)
上一篇 2025年3月7日 08:31:21
下一篇 2025年2月24日 06:32:35

AD推荐 黄金广告位招租... 更多推荐

相关推荐

发表回复

登录后才能评论