将动态顺风类添加到react组件(Next.JS+tailwind+TS)



我在尝试将动态顺风类分配给react组件时遇到了以下noob问题。

我在tailwind.config.js中扩展了我的主题颜色如下:

...
theme: {
extend: {
colors: {
blueGray: {
50: '#f6f9f9',
100: '#e4f1f8',
200: '#c2e0f0',
300: '#91c0db',
400: '#5b9bbf',
500: '#4479a3',
600: '#385f87',
700: '#2d4768',
800: '#203049',
900: '#131d2f',
},
// OTHER COLORS
},
},
},
...

我的反应组件如下:

import Draggable from 'react-draggable';
type SensorProps = {
name: string
color: string
}
export default function Sensor(props : SensorProps): JSX.Element {
return (
<Draggable
axis="both"
bounds="flow-canvas">
<div className={`border-${props.color}-400  bg-${props.color}-50 text-${props.color}-700`}>
<p> {props.name} </p>
</div>
</Draggable>
)
}

以下是我如何实例化传感器组件的一些示例

<Sensor name={"Water Level"} color={"blueGray"} />
<Sensor name={"Flow"} color={"mGreen"} />

问题是没有应用这些类,但当我检查页面时,div有正确的类。

如果切换自:

<div className={`border-${props.color}-400  bg-${props.color}-50 text-${props.color}-700`}>

至:

<div className={`border-blueGray-400  bg-blueGray-50 text-blueGray-700`}>

它起作用:(

我已经在使用顺风JIT编译器

...
mode: 'jit',
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
...

有什么建议吗?

顺风编译器在编译时解析代码,并清除它认为在任何地方都没有使用的类。您没有直接使用border-blueGray-400,因此它将其视为未使用的类,并将其从捆绑包中删除以提高性能。

在我看来,最好的解决方案是不传递任意的道具,如colorsize等,而是传递className属性。

因此,您可以这样呈现您的组件:

<Sensor className="border-blueGray-400 bg-blueGray-50 text-blueGray-700" />

在子组件中:

<div className={props.className} />

现在您可以使用

<div className={`border-${props.color}-400  bg-${props.color}-50 text-${props.color}-700`}>

通过在tailwindcss 中使用安全列表类


说明

是否建议在tailwind中使用dynamic class

通常不建议在tailwind-css中使用dynamic classes,因为tailwind使用tree-shaking,即任何未在源文件中声明的类都不会在输出文件中生成。

因此,始终建议使用完整类名

根据文件

如果使用字符串插值或将部分类名连接在一起,Tailwind将找不到它们,因此不会生成相应的CSS

周围没有工作吗

作为最后的手段,Tailwind提供安全登录课程。

安全列表是最后的手段,只应在无法扫描某些内容以查找类名的情况下使用。这种情况很少见,您几乎永远都不需要此功能。

在您的示例中,您希望有100 500 700色调的颜色。可以使用正则表达式来包含使用pattern所需的所有颜色,并相应地指定阴影。

tailwind.config.js

module.exports = {
content: [
'./pages/**/*.{html,js}',
'./components/**/*.{html,js}',
],
safelist: [
{
pattern: /bg-(red|green|blue|orange)-(100|500|700)/, // You can display all the colors that you need
},
],
// ...
}

额外:如何自动在safelist
中拥有所有顺风颜色
const tailwindColors = require("./node_modules/tailwindcss/colors")
const colorSafeList = []
// Skip these to avoid a load of deprecated warnings when tailwind starts up
const deprecated = ["lightBlue", "warmGray", "trueGray", "coolGray", "blueGray"]
for (const colorName in tailwindColors) {
if (deprecated.includes(colorName)) {
continue
}
// Define all of your desired shades
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]
const pallette = tailwindColors[colorName]
if (typeof pallette === "object") {
shades.forEach((shade) => {
if (shade in pallette) {
colorSafeList.push(`text-${colorName}-${shade}`)
colorSafeList.push(`bg-${colorName}-${shade}`)
colorSafeList.push(`border-${colorName}-${shade}`)
}
})
}
}
// tailwind.config.js
module.exports = {
safelist: colorSafeList,                      // <-- add the safelist here
content: ["{pages,app}/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: tailwindColors,
},
},
plugins: [],
}

使用内联CSS

当我动态生成具有相同设计但不同文本和按钮颜色的jsx时,我偶然发现了这个问题。这可能有点棘手,因为在开发时,它看起来很好,所有的类都正确呈现,但快速重新启动dev-server似乎可以从最终捆绑包中完全删除这些类。诅咒git几分钟后,我有了直觉,发现了这条线索。

对于任何未来的读者来说,在不使用外部库和safelisting顺风类膨胀风险的情况下,最优雅的解决方案是使用内联样式,即style = {{ color: INSERT_VARIABLE_HERE }},您可以继续使用。

工作代码:

// Generate modals for different types
// All use the same design
// IMPORTANT: Tailwind cannot deduce partial class names sent as arguments, and
// removes them from final bundle, safe to use inline styling
const _generateModal = (
initialTitle: string,
image: string,
buttonColor: string,
bgColor: string = "white",
textColor: string = "rgb(55 65 81)",
buttonText: string = "Continue"
) => {
return ({ title = initialTitle, text, isOpen, onClose }: Props) => {
if (!isOpen) return null;
return ReactDom.createPortal(
<div className="fixed inset-0 bg-black bg-opacity-80">
<div className="flex h-full flex-col items-center justify-center">
<div
className={`relative flex h-1/2 w-1/2 flex-col items-center justify-evenly rounded-xl lg:w-1/4`}
style={{ color: textColor, backgroundColor: bgColor }}
>
<RxCross2
className="absolute top-0 right-0 mr-5 mt-5 cursor-pointer text-2xl"
onClick={() => onClose()}
/>
<h1 className="text-center text-3xl font-thin">{title}</h1>
<h3 className="text-center text-xl font-light tracking-wider opacity-80">
{text}
</h3>
<img
src={image}
alt="info image"
className="hidden w-1/6 lg:block lg:w-1/4"
/>
<button
onClick={() => onClose()}
className={`rounded-full px-16 py-2 text-xl text-white`}
style={{ backgroundColor: buttonColor }}
>
{buttonText}
</button>
</div>
</div>
</div>,
document.getElementById("modal-root") as HTMLElement
);
};
};
export const SuccessModal = _generateModal(
"Success!",
checkimg,
"rgb(21 128 61)" // green-700
);
export const InfoModal = _generateModal(
"Hey there!",
infoimg,
"rgb(59 130 246)" // blue-500
);
export const ErrorModal = _generateModal(
"Face-plant!",
errorimg,
"rgb(190 18 60)", // rose-700
"rgb(225 29 72)", // rose-600
"rgb(229 231 235)", // gray-200
"Try Again"
);

我在这里使用reactjs和typescript,这里的代码可以用来生成3种类型的弹出模式,InfoModalErrorModalSuccessModal。jsx生成器可以通过为我们编写代码来帮助缓解这些问题,而不是在任何地方都编写相同的样板代码,其中更新一个代码需要在3个地方进行更新

您可以使用clsx这样的库有条件地呈现类。然后您的子组件将呈现:

<div className={clsx(
"border-blueGray-400 bg-blueGray-50 text-blueGray-700": props.color === "blueGray",
"border-mGray-400 bg-mGray-50 text-mGray-700": props.color === "mGray",
)} />

如果您只想修改一个或两个属性,这不是一个好的解决方案。然后我建议直接通过顺风课程作为道具,就像另一个答案中提到的那样。

但是,如果您有一些更复杂的逻辑,比如依赖于类的多个css属性,这个解决方案可能是好的。

最新更新