首頁  >  文章  >  web前端  >  使無頭組件易於設計

使無頭組件易於設計

王林
王林原創
2024-08-23 14:30:35385瀏覽

Making headless components easy to style

無頭組件只是一個無樣式組件,還是還有更多內容?

網路已經透過要求定義樣式將樣式與內容分開
在 CSS 中而不是 HTML 中。這種架構讓每個網頁都採用全域
設計標準,無需定義任何特定於頁面的樣式。

隨著網路演變成一個應用程式平台,開發人員尋找方法
他們不斷增長的程式碼庫更易於維護。如今,事實上的策略
組織應用程式程式碼就是定義小型、輕量級的元件,這些元件可以
一起組成。因此,組件成為
中的組成單位 現代網路開發。

為了封裝,元件通常同時定義 HTML 和 CSS。
雖然這使它們更容易創作,但它們可能更難
緊密結合到現有的設計系統。這一點尤其正確
適用於從外部供應商匯入的第三方元件。

無頭組件透過重新引入
之間的分離來解決這項挑戰 內容和風格。然而現在分離是沿著組件邊界的
反對 HTML 和 CSS 之間的關係。它們是創建出色的無頭組件的關鍵
關鍵在於設計組件的接口,以便開發人員可以
清晰、輕鬆地應用自己的風格。

轉發相關道具

從最基本的意義上來說,無頭組件只是一個無樣式的元件。
開發人員必須能夠將自己的 CSS 應用到
的 HTML 元素 組件定義。

對於簡單的元件,這可能只是轉發 className
prop 到根元素,以便開發人員可以在他們的
中使用類別選擇器 CSS。

如果您的元件與原生 HTML 元素具有相同的語義,您可以使用
React 中的 ComponentProps 類型,以確保所有相關的 props 都是
可轉發。請記得省略任何您不希望使用者使用的道具
您的組件能夠覆蓋。

import { type ComponentProps } from 'react'

function SubmitButton({ ...props }: Omit<ComponentProps<'button'>, 'type'>) {
  return <button type="submit" {...props} />
}

提供預定義類

對於包含一個或多個子元素的元件,開發人員可能會
想要單獨設定每個元素的樣式。

支持這一點的一個策略是依賴
CSS 組合器。
例如,無頭畫廊組件的樣式可能如下:

/* Root container */
.gallery {
}

/* Gallery items container */
.gallery > ul {
}

/* Gallery item */
.gallery > ul > li {
}

/* Next and Previous buttons */
.gallery button {
}

但這種方法產生了一個巨大的問題,因為現在
的內部HTML結構 該元件是其公共 API 的一部分。這會阻止您修改
稍後構造,而不會破壞下游代碼。

更好的策略是為每個主要子元素預先定義類別。這邊
開發人員可以使用類別選擇器,而不依賴任何特定的 HTML
結構:

.xyz-gallery {
}

.xyz-gallery-next-button {
}

.xyz-gallery-previous-button {
}

.xyz-gallery-items-container {
}

.xyz-gallery-item {
}

記得為你的類別加上前綴,這樣它們就不會與
衝突 開發者自己的風格。

支援自訂佈局

提供預先定義的類別可能是使開發人員能夠
的最快方法 設定你的組件的樣式。然而,這種方法的一個缺點是
HTML 結構無法自訂。

這可能並不重要。畢竟,純 HTML 的使用方式已經相當靈活了
可以渲染。然而,有時開發人員會依序取得額外的 HTML
來完成某些設計。如果您查看幾乎所有
的源代碼 網站,您可能會看到大量無語義的

。元素,
其唯一目的是定義彈性或網格佈局,直觀地對子元素進行分組
邊框內的元素或建立新的堆疊上下文。

您可以透過將無頭組件拆分為
來支援此類用例 多個相關組件。這樣開發者就可以自由加入自己的
將元素佈局到元件。例如,開發人員可以嵌入 Next 和
自訂 Flexbox 容器中圖庫範例中的上一個按鈕:

<Gallery>
  <GalleryItems className='gallery-items-container'>
    {data.map((item) => (
      <GalleryItem key={item.id}>{item.content}</GalleryItem>
    ))}
  </GalleryItems>
  <div className='gallery-buttons-container'>
    <GalleryPreviousButton>
    <GalleryNextButton>
  </div>
</Gallery>
.gallery-items-container {
}

.gallery-buttons-container {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

這些類型的元件通常使用
來實現 要傳遞的上下文
它們之間的數據。他們需要更多的工作來設計、實施和
文件.然而,它們所帶來的多功能性通常意味著額外的努力
值得。

允許組件被覆蓋

少數用例需要無頭元件來管理佈局
其子組件。一個例子可能是分層樹視圖
允許透過拖放對其項目進行重新排序。另一個用例可能是
允許單頁應用程式以
取代預設的錨元素 有助於客戶端路由的自訂連結元件。

An advanced strategy for allowing developers to define custom layouts is to
allow the actual child component being rendered to be overriden via props:

<TreeView
  nodes={[...]}
  components={{
    CustomRow,
    CustomDragPreview: (props) => <div className="drag-preview" {...props} />
  }}
/>

This grants the developer full control over what is rendered in each child
component, while allowing the headless component to manage its overall
structure.

You can even allow developers to customise the root element of your component
via a prop. For example, this button component allows a developer to render it
as something else:

import { type ElementType } from 'react'

function HeadlessButton({ as, ...props }: { as?: ElementType }) {
  const Component = as ?? 'button'
  return <Component {...props} />
}

For example, in order for assistive technology to treat the button like a link,
the developer can specify that an anchor element should be used to render the
button:

<HeadlessButton as="a">Actually a link</HeadlessButton>

Summary

Headless components are much more than components that don't contain any
styles. Great headless components are fully extensible and allow the developer
to customise the entire internal HTML structure.

以上是使無頭組件易於設計的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn