搜尋
首頁web前端css教學並非所有東西都需要組件

並非所有東西都需要組件

Nov 26, 2024 am 03:32 AM

Not Everything Needs a Component

2000 年代初期,創造了一個新術語Divitis,用來指稱使用許多div 元素編寫網頁程式碼的做法有意義的語義HTML元素 的位置。這是在漸進增強技術框架內提高 HTML 語義意識的努力的一部分。

快轉 20 年 - 我目睹了一種影響網絡開發者的新綜合症,我稱之為組件炎。這是我編的定義:

元件化:為 UI 的各個面向建立元件來取代更簡單、更可重複使用的解決方案的做法。

成分

那麼,首先,什麼是組件?我認為 React 普及了這個術語來指稱它的構建塊:

React 可讓您將標記、CSS 和 JavaScript 組合到自訂「元件」中,應用程式的可重複使用 UI 元素。
React 文件 - 您的第一個元件

雖然可重複使用 UI 元素的概念在當時並不新鮮(在 CSS 中,我們已經有了 OOCSS、SMACSS 和 BEM 等技術),但關鍵的區別在於它對標記、樣式和元素位置的原始方法。相互作用。使用 React 元件(以及所有後續 UI 庫),可以將所有內容共同定位在元件邊界內的單一檔案中。

因此,使用 Facebook 最新的 CSS 庫 Stylex,您可以編寫:

import * as stylex from "@stylexjs/stylex";
import { useState } from "react";

// styles
const styles = stylex.create({
    base: {
        fontSize: 16,
        lineHeight: 1.5,
        color: "#000",
    },
});

export function Toggle() {
    // interactions
    const [toggle, setToggle] = useState(false);
    const onClick = () => setToggle((t) => !t);

    // markup
    return (
        <button type="button" onclick="{onClick}">
            {toggle}
        </button>
    );
}

你可能喜歡或不喜歡用對象表示法編寫CSS(我不是),但這種級別的共置通常是使基於組件的項目更易於維護的好方法:一切都觸手可及,並且明確綁定。

在像 Svelte 這樣的函式庫中,共置更加清晰(且程式碼更加簡潔):

<script>
    let toggle = $state(false)
    const onclick = () => toggle = !toggle
</script>

<button type="button">
    {toggle}
</button>

<style>
button {
    font-size: 16px;
    line-height: 1.5;
    color: #000;
}
</style> 

隨著時間的推移,這種模式獲得瞭如此大的吸引力,以至於所有東西都封裝在組件中。您可能曾經遇到這樣的頁面元件:

export function Page() {
    return (
        <layout>
            <header nav="{<Nav"></header>} />
            
                <stack spacing="{2}">
                    <item>Item 1</item>
                    <item>Item 2</item>
                    <item>Item 3</item>
                </stack>
            
            <footer></footer>
        </layout>
    );
}

並置一處

上面的程式碼看起來乾淨且一致:我們使用元件介面來描述頁面。

那麼,讓我們來看看 Stack 的可能實作。該組件通常是一個包裝器,以確保所有直接子元素垂直堆疊且均勻分佈:

import * as stylex from "@stylexjs/stylex";
import type { PropsWithChildren } from "react";

const styles = stylex.create({
    root: {
        display: "flex",
        flexDirection: "column",
    },
    spacing: (value) => ({
        rowGap: value * 16,
    }),
});

export function Stack({
    spacing = 0,
    children,
}: PropsWithChildren) {
    return (
        <div styles.spacing>
            {children}
        </div>
    );
}

我們只定義元件的樣式和根元素。

在這種情況下,我們甚至可以說我們唯一共同定位的是樣式塊,因為 HTML 僅用於保存 CSS 類引用,並且沒有交互性或業務邏輯。

靈活性的(可避免的)成本

現在,如果我們希望能夠將根元素呈現為一個部分並可能添加一些屬性怎麼辦?我們需要進入多態組件的領域。在 React 和 TypeScript 中,這最終可能類似於以下內容:

import * as stylex from "@stylexjs/stylex";
import { useState } from "react";

// styles
const styles = stylex.create({
    base: {
        fontSize: 16,
        lineHeight: 1.5,
        color: "#000",
    },
});

export function Toggle() {
    // interactions
    const [toggle, setToggle] = useState(false);
    const onClick = () => setToggle((t) => !t);

    // markup
    return (
        <button type="button" onclick="{onClick}">
            {toggle}
        </button>
    );
}

在我看來,乍看之下這不是很可讀。請記住:我們只是用 3 個 CSS 宣告來渲染一個元素。

回到基礎知識

不久前,我正在用 Angular 開發一個寵物專案。由於習慣了用組件來思考,我聯繫他們創建了一個堆疊。事實證明,在 Angular 中,多型元件的創建更加複雜。

我開始質疑我的實作設計,然後我突然頓悟:當解決方案一直就在我面前時,為什麼還要花時間和程式碼行來實現複雜的實作?

<script>
    let toggle = $state(false)
    const onclick = () => toggle = !toggle
</script>

<button type="button">
    {toggle}
</button>

<style>
button {
    font-size: 16px;
    line-height: 1.5;
    color: #000;
}
</style> 

真的,這就是 Stack 的準系統 本機 實作。在佈局中載入 CSS 後,就可以立即在程式碼中使用它:

export function Page() {
    return (
        <layout>
            <header nav="{<Nav"></header>} />
            
                <stack spacing="{2}">
                    <item>Item 1</item>
                    <item>Item 2</item>
                    <item>Item 3</item>
                </stack>
            
            <footer></footer>
        </layout>
    );
}

在 JavaScript 框架中新增類型安全

純 CSS 解決方案既不提供打字功能,也不提供 IDE 自動完成功能。

此外,如果我們不使用間距變體,那麼編寫類別和樣式屬性而不是間距屬性可能會感覺太冗長。假設您正在使用 React,您可以利用 JSX 並建立一個實用函數:

import * as stylex from "@stylexjs/stylex";
import type { PropsWithChildren } from "react";

const styles = stylex.create({
    root: {
        display: "flex",
        flexDirection: "column",
    },
    spacing: (value) => ({
        rowGap: value * 16,
    }),
});

export function Stack({
    spacing = 0,
    children,
}: PropsWithChildren) {
    return (
        <div styles.spacing>
            {children}
        </div>
    );
}

請注意,React TypeScript 不允許未知的 CSS 屬性。為了簡潔起見,我使用了類型斷言,但您應該選擇更強大的解決方案。

如果您使用變體,您可以修改實用函數以提供類似於 PandaCSS 模式的開發人員體驗:

import * as stylex from "@stylexjs/stylex";

type PolymorphicComponentProps<t extends react.elementtype> = {
    as?: T;
    children?: React.ReactNode;
    spacing?: number;
} & React.ComponentPropsWithoutRef<t>;

const styles = stylex.create({
    root: {
        display: "flex",
        flexDirection: "column",
    },
    spacing: (value) => ({
        rowGap: value * 16,
    }),
});

export function Stack<t extends react.elementtype="div">({
    as,
    spacing = 1,
    children,
    ...props
}: PolymorphicComponentProps<t>) {
    const Component = as || "div";
    return (
        <component styles.spacing>
            {children}
        </component>
    );
}
</t></t></t></t>

防止程式碼重複和硬編碼值

你們中的一些人可能已經注意到,在最後一個範例中,我在 CSS 和實用程式檔案中硬編碼了間距的預期值。如果刪除或新增某個值,這可能會成為一個問題,因為我們必須保持兩個檔案同步。

如果您正在建立一個庫,自動化視覺回歸測試可能會發現此類問題。無論如何,如果它仍然困擾您,解決方案可能是使用 CSS 模組並使用 typed-css-modules 或針對不支援的值拋出運行時錯誤:

<div>





<pre class="brush:php;toolbar:false">.stack {
  --s: 0;
    display: flex;
    flex-direction: column;
    row-gap: calc(var(--s) * 16px);
}
export function Page() {
    return (
        <layout>
            <header nav="{<Nav"></header>} />
            
                <div classname="stack">



<p>Let's see the main advantages of this approach:</p>

<ul>
<li>reusability</li>
<li>reduced complexity</li>
<li>smaller JavaScript bundle and less overhead</li>
<li><strong>interoperability</strong></li>
</ul>

<p>The last point is easy to overlook: Not every project uses React, and if you’re including the stack layout pattern in a Design System or a redistributable UI library, developers could use it in projects using different UI frameworks or a server-side language like PHP or Ruby.</p>

<h2>
  
  
  Nice features and improvements
</h2>

<p>From this base, you can iterate to add more features and improve the developer experience. While some of the following examples target React specifically, they can be easily adapted to other frameworks.</p>

<h3>
  
  
  Control spacing
</h3>

<p>If you're developing a component library you definitely want to define a set of pre-defined spacing variants to make space more consistent. This approach also eliminates the need to explicitly write the style attribute:<br>
</p>

<pre class="brush:php;toolbar:false">.stack {
  --s: 0;
  display: flex;
  flex-direction: column;
  row-gap: calc(var(--s) * 16px);

  &.s\:1 { --s: 1 }
  &.s\:2 { --s: 2 }
  &.s\:4 { --s: 4 }
  &.s\:6 { --s: 6 }
}

/** Usage:
<div>



<p>For a bolder approach to spacing, see Complementary Space by Donnie D'Amato.</p>

<h3>
  
  
  Add better scoping
</h3>

<p>Scoping, in this case, refers to techniques to prevent conflicts with other styles using the same selector. I’d argue that scoping issues affects a pretty small number of projects, but if you are really concerned about it, you could:</p>

<ol>
<li>Use something as simple as CSS Modules, which is well supported in all major bundlers and frontend frameworks.</li>
<li>Use cascade layers resets to prevent external stylesheets from modifying your styles (this is an interesting technique).</li>
<li>Define a specific namespace like .my-app-... for your classes.</li>
</ol>

<p>Here is the result with CSS Modules:<br>
</p>

<pre class="brush:php;toolbar:false">.stack {
  --s: 0;
  display: flex;
  flex-direction: column;
  row-gap: calc(var(--s) * 16px);

  &.s1 { --s: 1 }
  &.s2 { --s: 2 }
  &.s4 { --s: 4 }
  &.s6 { --s: 6 }
}

/** Usage
import * from './styles/stack.module.css'

<div classname="{`${styles.stack}">
    // ...
</div>  
*/

替代方案

如果你仍然認為多態元件會更好,確實無法處理純HTML,或者不想在單獨的檔案中編寫CSS(雖然我不確定為什麼),我的下一個建議是看看PandaCSS 並建立自訂模式或探索其他選項,例如vanilla-extract。在我看來,這些工具是一種過度設計的 CSS 元語言,但仍然比多態元件更好。

另一個值得考慮的替代方案是 Tailwind CSS,它具有語言和框架之間可互通的優點

使用 Tailwind 定義的預設間距比例,我們可以建立一個如下所示的堆疊插件:

import * as stylex from "@stylexjs/stylex";
import { useState } from "react";

// styles
const styles = stylex.create({
    base: {
        fontSize: 16,
        lineHeight: 1.5,
        color: "#000",
    },
});

export function Toggle() {
    // interactions
    const [toggle, setToggle] = useState(false);
    const onClick = () => setToggle((t) => !t);

    // markup
    return (
        <button type="button" onclick="{onClick}">
            {toggle}
        </button>
    );
}

順便說一句:有趣的是,Tailwind 使用 matchComponents 中的組件心智模型來描述複雜的 CSS 規則集,即使它沒有創建任何 真實 組件。也許另一個例子可以說明這個概念是多麼普遍?

重點

成分炎的案例,除了技術方面之外,還表明了停下來檢查和質疑我們的心理模式和習慣的重要性。與軟體開發中的許多模式一樣,元件的出現是為了解決實際問題,但是當我們開始預設這種模式時,它就成為了複雜性的無聲來源。 成分炎類似於限制飲食引起的營養缺乏:問題不在於任何單一食物,而在於錯過了其他一切。

以上是並非所有東西都需要組件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
這不應該發生:對不可能進行故障排除這不應該發生:對不可能進行故障排除May 15, 2025 am 10:32 AM

解決這些不可能的問題之一,這是您從未想過的其他問題的問題。

@KeyFrames vs CSS過渡:有什麼區別?@KeyFrames vs CSS過渡:有什麼區別?May 14, 2025 am 12:01 AM

@keyframesandCSSTransitionsdifferincomplexity:@keyframesallowsfordetailedanimationsequences,whileCSSTransitionshandlesimplestatechanges.UseCSSTransitionsforhovereffectslikebuttoncolorchanges,and@keyframesforintricateanimationslikerotatingspinners.

使用頁面CMS進行靜態站點內容管理使用頁面CMS進行靜態站點內容管理May 13, 2025 am 09:24 AM

我知道,我知道:有大量的內容管理系統選項可用,而我進行了幾個測試,但實際上沒有一個是一個,y&#039;知道嗎?怪異的定價模型,艱難的自定義,有些甚至最終成為整個&

鏈接HTML中CSS文件的最終指南鏈接HTML中CSS文件的最終指南May 13, 2025 am 12:02 AM

鏈接CSS文件到HTML可以通過在HTML的部分使用元素實現。 1)使用標籤鏈接本地CSS文件。 2)多個CSS文件可通過添加多個標籤實現。 3)外部CSS文件使用絕對URL鏈接,如。 4)確保正確使用文件路徑和CSS文件加載順序,優化性能可使用CSS預處理器合併文件。

CSS Flexbox與網格:全面評論CSS Flexbox與網格:全面評論May 12, 2025 am 12:01 AM

選擇Flexbox還是Grid取決於佈局需求:1)Flexbox適用於一維佈局,如導航欄;2)Grid適合二維佈局,如雜誌式佈局。兩者在項目中可結合使用,提升佈局效果。

如何包括CSS文件:方法和最佳實踐如何包括CSS文件:方法和最佳實踐May 11, 2025 am 12:02 AM

包含CSS文件的最佳方法是使用標籤在HTML的部分引入外部CSS文件。 1.使用標籤引入外部CSS文件,如。 2.對於小型調整,可以使用內聯CSS,但應謹慎使用。 3.大型項目可使用CSS預處理器如Sass或Less,通過@import導入其他CSS文件。 4.為了性能,應合併CSS文件並使用CDN,同時使用工具如CSSNano進行壓縮。

Flexbox vs Grid:我應該學習兩者嗎?Flexbox vs Grid:我應該學習兩者嗎?May 10, 2025 am 12:01 AM

是的,youshouldlearnbothflexboxandgrid.1)flexboxisidealforone-demensional,flexiblelayoutslikenavigationmenus.2)gridexcelstcelsintwo-dimensional,confffferDesignssignssuchasmagagazineLayouts.3)blosebothenHancesSunHanceSlineHancesLayOutflexibilitibilitibilitibilitibilityAnderibilitibilityAndresponScormentilial anderingStruction

軌道力學(或我如何優化CSS KeyFrames動畫)軌道力學(或我如何優化CSS KeyFrames動畫)May 09, 2025 am 09:57 AM

重構自己的代碼看起來是什麼樣的?約翰·瑞亞(John Rhea)挑選了他寫的一個舊的CSS動畫,並介紹了優化它的思維過程。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境