Rumah > hujung hadapan web > tutorial css > Pendekatan berbeza untuk menulis varian komponen dengan Tailwind CSS

Pendekatan berbeza untuk menulis varian komponen dengan Tailwind CSS

Patricia Arquette
Lepaskan: 2024-11-21 05:35:11
asal
646 orang telah melayarinya

A different approach to writing component variants with Tailwind CSS

Masalahnya

Secara tradisinya apabila menulis varian komponen dengan Tailwind CSS, saya telah mencapai peta kelas mudah yang memetakan nilai prop pada slot komponen:

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>
Salin selepas log masuk

Masalah dengan pendekatan ini ialah memastikan kelas yang diperlukan sejajar antara satu sama lain, memastikan setiap varian mempunyai semua kelas yang diperlukan, terutamanya dalam komponen yang lebih rumit. Dalam komponen yang kami ingin berkongsi gaya, katakan warna teks, merentas slot komponen yang berbeza, kami memerlukan kami mengemas kini setiap slot secara individu.

Had Tailwind

Tailwind menjana kelas utiliti dengan mengimbas pangkalan kod anda dan rentetan yang sepadan, ini bermakna walaupun Tailwind boleh mencipta kelas daripada nilai sewenang-wenangnya, kami tidak boleh memulakannya secara dinamik tanpa membuat senarai selamat. Jadi ini tidak akan berfungsi:

// .ts
type TTheme = "DEFAULT" | "SECONDARY";

const colors: Record<TTheme, string> = {
  DEFAULT: "red",
  SECONDARY: "blue",
}

// .html
<div :class="`text-[${colors[DEFAULT]}]`">
Salin selepas log masuk

Walau bagaimanapun, kita boleh meniru tingkah laku yang diingini dengan memanfaatkan pembolehubah CSS, sesuatu yang digunakan oleh Tailwind di bawah hud untuk banyak kelasnya. Kita boleh menetapkan pembolehubah melalui kelas dalam Tailwind menggunakan sintaks berikut: [--my-variable-key:--my-variable-value]
Jadi bagaimana kita boleh mengemas kini contoh kod di atas untuk menggunakan nilai dinamik?

// .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]'
  ]">
Salin selepas log masuk

Menangani masalah awal

Kini kami memahami batasan Tailwind, kami perlu mencari cara untuk menyelesaikan masalah awal kami yang disebabkan oleh pendekatan peta kelas kami. Kita boleh mulakan dengan memudahkan peta kelas kita:

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>



<p>Unfortunately, this alone doesn't solve our problem, we still can't ensure we've set all of the classes we need to display each variant correctly. So how can we take this a step further? Well, we could begin writing an interface to force us to set specified values:<br>
</p>

<pre class="brush:php;toolbar:false">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]",
  },
}
Salin selepas log masuk

Jadi ini akan berjaya, tetapi, masih ada masalah, tiada apa yang menghalang kami daripada mencampurkan nilai rentetan kami. Contohnya, kami secara tidak sengaja boleh menetapkan latar belakang utama kepada [--text:blue].

Jadi mungkin kita patut menaip nilai kita juga. Kami tidak boleh menaip keseluruhan kelas, itu akan menjadi mimpi ngeri penyelenggaraan, jadi bagaimana jika kami menaip warna kami dan menulis kaedah pembantu untuk menjana pembolehubah CSS kami:

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",
  }),
}
Salin selepas log masuk

Baiklah, ini bagus, kami boleh memastikan kami sentiasa menetapkan pembolehubah yang betul untuk setiap varian komponen kami. Tetapi tunggu, kami baru sahaja menghadapi isu awal yang kami temui dengan Tailwind, kami tidak boleh menjana kelas sahaja, Tailwind tidak akan mengambilnya. Jadi bagaimana kita hendak menangani perkara ini?

Bagaimana pula dengan CSS dalam JS?

CSS dalam JS kelihatan seperti jawapan yang jelas di sini, cuma jana kelas yang mencipta kelas tersuai dengan pembolehubah yang betul. Tetapi terdapat halangan, Javascript berjalan pada klien, dan ini menyebabkan "Flash", di mana komponen pada mulanya dimuatkan tanpa pembolehubah ditetapkan sebelum mengemas kini untuk dipaparkan dengan betul.

Bagaimanakah CSS dalam perpustakaan JS menangani perkara ini?

Perpustakaan seperti Emosi menangani perkara ini dengan memasukkan teg gaya sebaris tentang komponen:

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



<p>This didn't feel like the right approach to me.</p>

<h3>
  
  
  So how do we solve this?
</h3>

<p>I was working with Vue, this led me down the path of v-bind in CSS, a feature in Vue to bind Javascript as CSS values. I'd only used this feature sparingly in the past and never taken a deep dive into what it's doing. v-bind in CSS simply sets an inline style on the relevant element.</p>

<p>This jogged my memory about a Tweet I saw from the creator of Tailwind CSS, Adam Wathan a couple of months previously:</p>

<p>So how does this help us? Well, while we can't dynamically generate Tailwind classes, we can dynamically generate inline styles and consume those inline styles from our Tailwind classes. So what would that look like?<br>
</p>

<pre class="brush:php;toolbar:false">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
 >



<h2>
  
  
  Conclusion
</h2>

<p>By combining the powers of Typescript, CSS variables, and inline styles we were able to ensure that while using Tailwind CSS, each variant of our component would have every option set and with the correct type.</p>

<p>This is an experimental approach on which I'm sure there will be some strong opinions. Am I convinced this is the best approach? At this stage, I'm not sure, but I think it has legs.</p>

<p>If you've found this article interesting or useful, please follow me on Bluesky (I'm most active here), Medium, Dev and/ or Twitter.</p>

<h3>
  
  
  Example: variableMap
</h3>



<pre class="brush:php;toolbar:false">// 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(" ");
};
Salin selepas log masuk

Atas ialah kandungan terperinci Pendekatan berbeza untuk menulis varian komponen dengan Tailwind CSS. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan