0

0

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

聖光之護

聖光之護

发布时间:2024-11-18 09:03:16

|

1043人浏览过

|

来源于dev.to

转载

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

问题

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

type ttheme = "default" | "secondary";
interface icomponentslot {
  root: string;
  accent: string;
}

const theme_map: record<ttheme, icomponentslot> = {
  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",
  }
}

<div :class="theme_map['default'].root">
  <div :class="theme_map['default'].accent">/**/</div>
</div>

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

tailwind 的局限性

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

// .ts
type ttheme = "default" | "secondary";

const colors: record<ttheme, string> = {
  default: "red",
  secondary: "blue",
}

// .html
<div :class="`text-[${colors[default]}]`">

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

// .ts
type ttheme = "default" | "secondary";

const colors: record<ttheme, string> = {
  default: "[--text-color:red]",
  secondary: "[--text-color:blue]",
}

// .html
<div
  :class="[
    colors[default],
    'text-[--text-color]'
  ]">

解决最初的问题

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

type ttheme = "default" | "secondary";
interface icomponentslot {
  root: string;
  accent: string;
}

const theme_map: record<ttheme, string> = {
  default: "[--backgound:red] [--hover__background:pink] [--text:blue] [--hover__text:green]",
  secondary: "[--backgound:green] [--hover__background:black] [--text:pink] [--hover__text:white]",
}

<div class="bg-[--background] hover:bg-[--hover__background]">
  <div class="text-[--text] hover:text-[--hover__text">/**/</div>
</div>

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

interface icomponentthemevariables {
  backgound: string;
  hover__backgound: string;
  text: string;
  hover__text: string;
}

const theme_map: record<ttheme, icomponentthemevariables> = {
  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 article

const theme_map: record<ttheme, string> = {
  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”,组件最初加载时没有设置变量,然后更新才能正确显示。

YIXUNCMS中秋专版2.0.4
YIXUNCMS中秋专版2.0.4

系统介绍:YIXUNCMS中专专版是易迅软件工作室在中秋节来临之即推出的专题模板建站系统,使用增强版后台管控系统,板板设计符合节日特点。易迅软件工作室恭祝全国人民中秋快乐。特别提示:由于网站页面的不同设计,部分后台功能未在前端进行体现。系统特点:1、采用目前流行的PHP语言编写,底层采用超轻量级框架作为系统支撑;2、页面布局使用DIV+CSS技术,遵循WEB标准,及大提高页面的浏览速度;3、使用应

下载

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

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

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

<body>
  <div>
    <style data-emotion-css="21cs4">.css-21cs4 { font-size: 12 }</style>
    <div class="css-21cs4">text</div>
  </div>
</body>

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

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

我正在使用 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 article

const theme_map: record<ttheme, string> = {
  default: variablemap({
    backgound: "red",
    text: "pink",
    hover__background: "blue",
    hover__text: "green",
  }),
  secondary: variablemap({
    backgound: "green",
    text: "black",
    hover__background: "pink",
    hover__text: "white",
  }),
}

<div
  class="bg-[--background] hover:bg-[--hover__background]"
  :style="theme_map['default']"
>
  <div class="text-[--text] hover:text-[--hover__text">/**/</div>
</div>

/*
output:
<div
  class="bg-[--background] hover:bg-[--hover__background]"
  style="--background: red; --text: pink; --hover__background: blue; --hover__text: green;"
>
  <div class="text-[--text] hover:text-[--hover__text">...</div>
</div>
*/

结论

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

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

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

示例:变量映射

// variableMap example
export const variableMap = <T extends Record<string, string>>(
  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(" ");
};

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

智谱清言 - 免费全能的AI助手
智谱清言 - 免费全能的AI助手

智谱清言 - 免费全能的AI助手

相关专题

更多
TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

40

2026.02.13

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

638

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

217

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1558

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

642

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1027

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

980

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

186

2025.07.29

Golang 生态工具与框架:扩展开发能力
Golang 生态工具与框架:扩展开发能力

《Golang 生态工具与框架》系统梳理 Go 语言在实际工程中的主流工具链与框架选型思路,涵盖 Web 框架、RPC 通信、依赖管理、测试工具、代码生成与项目结构设计等内容。通过真实项目场景解析不同工具的适用边界与组合方式,帮助开发者构建高效、可维护的 Go 工程体系,并提升团队协作与交付效率。

18

2026.02.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.4万人学习

CSS教程
CSS教程

共754课时 | 36.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号