<button class="bg-blue-600 text-gray-50 px-6 py-2 rounded shadow hover:bg-blue-700 hover:-translate-y-1 hover:shadow-md transition-all duration-500">点我</button>
Tailwind 的复用方式
使用 CSS 复用
使用 CSS 复用可能是很多人第一想法,毕竟像上面那个按钮那样,它的 class
属性太长了。我们可以将其抽取成一个 .btn
:
<button class="btn">点我</button>
相应的,在 CSS 文件里(比如 nextjs 的 styles/globals.css
)定义这个 .btn
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn {
@apply bg-blue-600 text-gray-50 px-6 py-2 rounded shadow hover:bg-blue-700 hover:-translate-y-1 hover:shadow-md transition-all duration-500;
}
}
这些带 @
前缀的,是 PostCSS 指令(这不是我们的关注点,如果你对 PostCSS 有兴趣,请自行搜索资料进行学习),其中:
@tailwind
是 Tailwind 定义的,用于引用其预定义的模块@layer
指定我们自定义的 CSS 隶属于哪个模块。很显然,因为我们是要定义一个按钮,所以它是属于components
@apply
允许在我们自定义的 CSS 里直接使用 Tailwind 预定义的 CSS 类
Tailwind 并不推荐通过 CSS 复用,而是通过下文说的,封装成React组件进行复用。但是,有时候我们避免不了要定义一些辅助性的样式,这时就可以按上面的方法进行定义。
本小节代码:axum-rs-nextjs-with-tailwind-btn-css
使用 React/NextJS 的组件进行复用
首先,我们创建一个 Button
组件:
// components/Button.jsx
export default function Button({ children }) {
return (
<button className="bg-blue-600 text-gray-50 px-6 py-2 rounded shadow hover:bg-blue-700 hover:-translate-y-1 hover:shadow-md transition-all duration-500">
{children}
</button>
);
}
<Button>点我</Button>
本小节代码:axum-rs-nextjs-with-tailwind-btn-1
复用原则
通过 React/NextJS/Vue 的组件进行复用 Tailwind。当需要一些辅助性的样式时,可以通过 CSS 进行定义。
扩展这个按钮组件
目前我们这个按钮组件只有一种蓝色,在实际项目中需要多种颜色,我们可以通过增加 color
来接收需要的颜色:
<Button>蓝色按钮</Button>
<Button color="red">红色按钮</Button>
<Button color="gray">灰色按钮</Button>
然后你可能在 Button
组件里这样写:
export default function Button({ children,color }) {
return (
<button className={`bg-${color}-600 text-gray-50 px-6 py-2 rounded shadow hover:bg-${color}-700 hover:-translate-y-1 hover:shadow-md transition-all duration-500`}>
{children}
</button>
);
}
这是一个严重的错误!
不要通过变量值来拼接 Tailwind 的类名
上面例子中,通过变量 color
的值,直接拼接了两个 tailwind 类:bg-${color}-600
和hover:bg-${color}-700
。这是行不通的!由于 tailwind 的体积非常大,所以利用 PostCSS 进行处理:只打包项目中真实用到的 tailwind 类,这样就能显著地减少项目的体积。
PostCSS 是按 tailwind 的类名进行处理的,它并不会处理 bg-${color}-600
这样的 JS 表达式,而是把它当成一个字符串,显然我们并没有定义 .bg-${color}-600
这样的 CSS 类,所以最终结果就是样式丢失。
而是通过JS的条件判断给定完整的 Tailwind 的类名
为了更具合理性,我们把上面说的 color
属性改为 type
属性:
<Button>蓝色按钮</Button>
<Button type="red">红色按钮</Button>
<Button type="gray">灰色按钮</Button>
然后实现 Button
组件:
export default function Button({ children, type }) {
let color = 'bg-blue-600';
let hoverColor = 'hover:bg-blue-700';
switch (type) {
case 'red': {
color = 'bg-red-600';
hoverColor = 'hover:bg-red-700';
break;
}
case 'gray': {
color = 'bg-gray-600';
hoverColor = 'hover:bg-gray-700';
break;
}
}
const classList = `${color} text-gray-50 px-6 py-2 rounded shadow ${hoverColor} hover:-translate-y-1 hover:shadow-md transition-all duration-500`;
return <button className={classList}>{children}</button>;
}
- 针对不同的
type
设置不同的颜色 - 把具体颜色和其它 CSS 类组成完整的列表
- 将这个列表传递给
<button>
元素
你或许会有疑问:
- 不是说 JSX 里只能用表达式吗,这里怎么跑出来了
switch
语句- 我们说的 JSX 是指具体的 JSX 语句,不是指
*.jsx
文件。 - 在
<button className={classList}>{children}</button>
里,只能用 JS 表达式,因为它是 JSX 语句;而在其它地方是 JS 环境,自然可以用包括语句在内的任何 JS 语法
- 我们说的 JSX 是指具体的 JSX 语句,不是指
classList
不也是在拼接吗- 它拼接的是完整的列表,里面的每一项都是完整的 CSS 类名
- 我们说的是不要拼接 CSS 类名