精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

2023年最火前端項目憑什么是它?

開發 前端
Shadcn UI 為開發者提供了一種全新的體驗,與現有的組件庫相比,它如一陣清風般令人耳目一新。它不僅加快了開發速度,還為開發者提供了對組件的精細控制,使他們能夠創造出獨特且富有創意的用戶界面。

近日,JavaScript Rising Stars 正式公布 2023 年 JavaScript 明星項目榜單,其中 shadcn/ui 位列榜首,2023 年獲得了 39.5k Star。本文將深入探討 shadcn/ui 是什么、使用方式、實現原理,它憑什么能夠成為年度最火前端項目!

概述

Shadcn UI 與其他 UI 和組件庫如 Material UI、Ant Design、Element UI 的設計理念截然不同。這些庫一般通過 npm 包提供對組件的訪問,而 Shadcn UI 允許用戶將單個 UI 組件的源代碼直接下載到項目中,提供了更大的靈活性和定制空間。

按照 Shadcn UI 的說法,Shadcn UI 實際上并不是一個組件庫,而是可以復制并粘貼到應用中的可重用組件的集合。

不到一年的時間,Shadcn UI 在 Github 上獲得了超過 40k Star。

Shadcn UI 相比其他組件庫提供了幾個顯著的優勢,其中最突出的包括:

  • 簡潔且易于使用:Shadcn UI為用戶提供了直觀且易于理解的文檔,可以輕松地開始使用。它不需要復雜的配置步驟,只需簡單的復制粘貼或使用CLI安裝即可快速集成到項目中。與其他組件庫相比,Shadcn UI簡化了開發流程,降低了學習曲線,可以專注于構建應用的核心功能。
  • 卓越的可訪問性:Shadcn UI 在設計之初就充分考慮到了可訪問性,確保其組件符合Web內容可訪問性指南(WCAG)標準。這意味著使用Shadcn UI構建的應用程序不僅外觀美觀,而且能夠適應各種用戶需求,無論是使用屏幕閱讀器、鍵盤導航還是其他輔助技術的用戶都能順利使用。
  • 精細控制與高度可定制:與其他UI庫不同,Shadcn UI允許直接訪問每個組件的源代碼。這意味著可以根據項目的具體需求輕松調整代碼,而無需受限于預定義的模板或樣式。這種高度的定制性提供了更大的靈活性,可以輕松地調整組件的外觀、行為和功能,以滿足項目的獨特要求。此外,這種可定制性還簡化了應用 的擴展和維護工作,使得長期開發變得更加高效。

在決定是否在未來的項目中采用Shadcn UI之前,有幾個關鍵因素值得考慮:

  • 安裝與配置:使用Shadcn UI可能需要一些手動工作。由于您需要單獨安裝或復制每個所需的組件,對于那些習慣于自動化的現代開發環境的人來說,這可能意味著額外的步驟和潛在的混亂。對于那些希望快速集成UI庫的人來說,這可能是一個挑戰。
  • 代碼庫大小與可維護性:Shadcn UI的直接源代碼訪問意味著您的項目代碼庫可能會增加,因為您需要包含每個組件的完整代碼。這可能會導致代碼行數增加,從而影響項目的可維護性和性能。對于大型項目或長期開發來說,這可能是一個重要的考慮因素。
  • 定制與擴展性:雖然Shadcn UI的直接源代碼訪問提供了高度定制化的機會,但這也意味著你可能需要更多的時間和資源來調整和擴展組件。對于需要高度定制化和靈活性的項目,這是一個優點;但對于需要快速集成的簡單應用程序,這可能不是最佳選擇。
  • 社區與支持:隨著時間的推移,一個活躍的社區和良好的支持是確保庫持續發展和更新的關鍵因素。Shadcn UI的社區規模和活躍度可能與更成熟的庫相比較少。因此,評估其社區的成熟度和可用資源是決定是否采用Shadcn UI的重要考慮因素。

功能

Shadcn UI 提供了很多功能,以增強用戶體驗。下面就來看看 Shadcn UI 中的幾個主要的功能:主題和主題編輯器暗黑模式CLI組件

主題和主題編輯器

Shadcn UI 提供了精選的主題,可以輕松地將其復制并粘貼到應用程序中。可以選擇通過代碼庫手動添加主題標記,或者使用 Shadcn UI 的主題編輯器進行更方便的操作。

主題編輯器允許配置各種屬性,如顏色、邊框半徑和模式(明亮或暗黑)。此外,還可以選擇兩種樣式:默認樣式和紐約樣式。每種樣式都具有獨特的組件、動畫和圖標。默認樣式具有較大的輸入字段、lucide-react圖標和用于動畫效果的tailwindcss-animate。而紐約樣式則包括較小的按鈕、帶陰影的卡片和Radix圖標。

使用Shadcn UI的圖形界面,創建自定義主題也非常簡單。編輯器會生成包含自定義樣式定義的代碼片段,只需將其復制粘貼到應用中即可。

shadcn-ui-theme-editor.gif下面是主題編輯器的代碼輸出示例,提供了淺色模式和深色模式的樣式標記:

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 221.2 83.2% 53.3%;
    --radius: 0.3rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 217.2 91.2% 59.8%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 224.3 76.3% 48%;
  }
}

暗黑模式

Shadcn UI 支持 Next.js 和 Vite 應用的暗黑模式。對于 Next.js 應用,Shadcn UI 使用next-themes來實現暗黑模式切換功能。當用戶在明亮模式和暗黑模式之間切換時,應用會在明亮和暗黑主題標記之間進行切換。

CLI

Shadcn UI 的 CLI 可以將庫與應用集成,并添加依賴項以及應用相關的tailwind.config.js配置。使用CLI還可以輕松地向應用程序添加UI組件。

可以選擇手動從文檔中復制和粘貼每個組件的代碼,或者使用CLI進行添加。CLI提供了優秀的開發者體驗,是使Shadcn UI更易于使用的一個功能。

組件

截至目前,Shadcn UI 擁有 40 個組件,包括 Accordion(手風琴)、Skeleton(骨架屏)、Table(表格)和Popover(彈出框)等。通過利用 Shadcn UI 預構建的組件,可以節省時間,而不必從頭開始構建組件。

使用

下面來看看如何將 Shadcn UI 與 Next.js 集成。

初始化

首先,通過運行以下命令創建一個新的 Next.js 應用:

npx create-next-app@latest my-app --typescript --tailwind --eslint

接下來,運行 init 命令來初始化新項目的依賴項:

npx shadcn-ui@latest init

CLI 將提示進行一些配置。以下是配置問題的示例:

Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? ? Default
Which color would you like to use as base color? ? Slate
Where is your global CSS file? ? ? app/globals.css
Do you want to use CSS variables for colors? ? no / yes
Where is your tailwind.config.js located? ? tailwind.config.js
Configure the import alias for components: ? @/components
Configure the import alias for utils: ? @/lib/utils
Are you using React Server Components? ? no / yes

現在就可以在應用中添加組件了,下面就來添加一個按鈕組件。

添加按鈕

可以運行以下命令以使用 CLI 添加一個按鈕:

npx shadcn-ui@latest add button

CLI 會自動創建一個組件文件夾,只需要從文件夾中導出它:

import { Button } from "@/components/ui/button"

<Button variant="outline">Button</Button>

按鈕組件的 variant 屬性有六種值:default、destructive、outline、secondary、ghost、link。

創建表單

Shadcn UI 在表單方面不僅提供了 Input、Textarea、Checkbox 和 RadioGroup 等表單組件,還提供了一個Form組件,該組件是 react-hook-form 的包裝器。下面來用 shadcn/ui 創建一個登錄表單。

Form 組件提供了一些功能:

  • <FormField /> 組件,用于構建受控表單字段
  • 支持使用表單驗證庫(如Valibot、Yup和Zod)進行驗證
  • 錯誤消息處理

可以運行以下命令來使用表單組件:

npx shadcn-ui@latest add form input

接下來,添加表單組件:

// use client  
  
import { zodResolver } from "@hookform/resolvers/zod";  
import { useForm } from "react-hook-form";  
import * as z from "zod";  
  
import { Button } from "@/components/ui/button";  
import {  
  Form,  
  FormControl,  
  FormDescription,  
  FormField,  
  FormItem,  
  FormLabel,  
  FormMessage,  
} from "@/components/ui/form";  
import { Input } from "@/components/ui/input";  
  
const FormSchema = z.object({  
  username: z.string().min(2, { message: "用戶名至少兩個字" }),  
});  
  
export function InputForm() {  
  const form = useForm({ resolver: zodResolver(FormSchema) });  
  
  function onSubmit(data) {  
    return (  
      <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">  
        {JSON.stringify(data, null, 2)}  
      </pre>  
    );  
  }  
  
  return (  
    <Form {...form}>  
      <form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">  
        <FormField control={form.control} name="username" render={({ field }) => (  
          <FormItem>  
            <FormLabel>Username</FormLabel>  
            <FormControl>  
              <Input placeholder="Input username" {...field} />  
            </FormControl>  
            <FormMessage />  
          </FormItem>  
        )} />  
        <Button type="submit">Submit</Button>  
      </form>  
    </Form>  
  );  
}

原理

Shadcn UI 組件的通用架構如下:

shadcn/ui基于核心原則構建,即組件的設計應與其實現分開。因此,shadcn/ui中的每個組件都具有兩層架構。即:

  • 結構和行為層
  • 樣式層

結構和行為層

在結構和行為層,組件以無頭形式實現,這意味著它們的結構組成和核心行為都被封裝在相應的表示中,這意味著組件的結構、布局和核心功能都在這一層進行定義和實現。此外,對于一些復雜的交互,如鍵盤導航和WAI-ARIA標準兼容性,也在這個層面進行考慮和實現。

為了支持這些復雜的功能和交互,shadcn/ui借助了一些成熟的、無頭(無界面)的UI庫。Radix UI 就是其中的一個關鍵庫,它在shadcn/ui的代碼庫中占有重要地位。許多常見的組件,如折疊面板(Accordion)、彈出框(Popover)、選項卡(Tabs)等,都是基于 Radix UI 的實現構建的。

對于滿足大多數組件需求,原生瀏覽器元素和Radix UI組件已經足夠了。但在某些情況下,需要使用更專業的無頭UI庫來滿足特定需求。

其中一種情況是表單處理。為了處理表單,shadcn/ui提供了一個基于React Hook Form無頭表單庫的Form組件。這個組件負責管理表單的狀態,而shadcn/ui則通過組合的方式,利用React Hook Form提供的基元進行了進一步的封裝。

對于表格視圖的處理,shadcn/ui 選擇了 Tanstack React Table 這個無頭表格庫。它的TableDataTable組件都是基于這個庫構建的。Tanstack React Table 提供了豐富的 API,用于處理表格視圖的各種交互,如過濾、排序和虛擬化。

另外,對于一些復雜的日期選擇組件,如日歷視圖、DateTime選擇器和DateRange選擇器,shadcn/ui 選擇了 React Day Picker 這個庫作為基礎組件,以實現這些組件的無頭層。這些組件往往難以正確實現,但通過使用 React Day Picker, shadcn/ui 確保了它們的正確性和易用性。

樣式層

TailwindCSS 是 shadcn/ui 樣式層的核心。顏色、邊框半徑等屬性值作為CSS變量存放在global.css文件中,以便于全局管理。這些變量可以跨設計系統共享,使用 Figma 等設計工具時,可以追蹤并同步Figma的變量。

為了區分組件的樣式,shadcn/ui引入了Class Variance Authority(CVA)。CVA提供了一個強大的API,允許我們為每個組件定制其樣式。

shadcn/ui Badge

在探討了 shadcn/ui 的架構后,下面來深入了解一些組件的具體實現,先從最簡單的組件開始。

import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const badgeVariants = cva(
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
  {
    variants: {
      variant: {
        default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
        secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
        destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
        outline: "text-foreground",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);

export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
  return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}

export { Badge, badgeVariants };

組件的實現始于對 class-variance-authority 中的 cva 函數的調用,它被用于聲明組件的不同變體。

const badgeVariants = cva(
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
  {
    variants: {
      variant: {
        default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
        secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
        destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
        outline: "text-foreground",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);

cva函數的第一個參數為<Badge/>組件的所有變體定義了基本樣式。作為第二個參數,cva接收一個配置對象,該對象規定了組件的可能變體以及應使用的默認變體。需要注意的是,實用樣式采用了tailwind.config.js中定義的設計系統標記,這使得只需調整 CSS 變量,就能輕松更新整體的外觀。

調用cva函數后會返回另一個函數,該函數可根據條件為各個變體應用相應的樣式。將其存儲在名為badgeVariants的變量中,以便在向組件傳遞變體名稱作為屬性時,能夠利用它應用正確的樣式。

接下來,我們可以找到定義組件類型的BadgeProps接口:

export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}

Badge 組件基于HTML的div元素。為了方便使用,該組件被設計為div元素的擴展。這一目標通過擴展React.HTMLAttributes<HTMLDivElement>類型來實現。此外,為了滿足不同需求,組件添加了一個variant屬性,允許使用者選擇并呈現所需的組件變體。VariantProps這一輔助類型以枚舉的形式在variant屬性上呈現可用的變體,進一步增強了組件的靈活性和易用性。

function Badge({ className, variant, ...props }: BadgeProps) {
  return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}

最終,我們得到了定義 Badge 的函數組件。在此組件中,除了 className 和 variant 之外的所有 props 都被收集到一個對象中,并通過擴展語法傳遞給底層的 div 元素。這使得組件使用者能夠與 div 元素上可用的所有 props 進行交互。

值得注意的是,組件中處理樣式應用的方式。variant 的值被傳遞到 badgeVariants 函數中,該函數返回一個包含渲染組件變體所需的所有實用程序類名的 class 字符串。此外,還有一個名為 cn 的函數,它將前述函數的返回值和傳遞到 className 中的值合并,然后計算為 div 元素的 className 屬性。

cn 函數是 shadcn/ui 提供的一個特殊實用函數,用于管理實用程序類。接下來,我們將深入探討它的實現。

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

這個實用函數是兩個庫的結合體,用于管理實用程序類。第一個庫是 clsx。它提供了通過 className 連接來有條件地應用樣式到組件的能力。

import React from "react";

const Link = ({ isActive, children }: { isActive: boolean, children: React.ReactNode }) => {
  return <a className={clsx("text-lg", { "text-blue-500": isActive })}>{children}</a>;
};

從上述代碼中可以看到 clsx 獨立使用的情形。在默認情況下,只有 text-lg 實用類被應用于 Link 組件。但當將 isActive 屬性傳遞給組件并設置為 true 時,text-blue-500 實用類也會被應用于該組件。

然而,在某些情況下,僅使用 clsx 無法實現我們的目標。

import React from "react";
import clsx from "clsx";

const Link = ({ isActive, children }: { isActive: boolean, children: React.ReactNode }) => {
  return <a className={clsx("text-lg text-grey-800", { "text-blue-500": isActive })}> {children}</a>;
};

在此情況下,元素默認應用了顏色實用類 text-grey-800。我們的目標是在 isActive 變為 true 時將文本顏色更改為 blue-500。但由于 CSS 的層疊性質,Tailwind 中的 text-grey-800 應用的顏色樣式無法被修改。

此時就需要使用 tailwind-merge庫。使用 tailwind-merge 修改上述代碼:

import React from "react";
import { twMerge } from "tailwind-merge";
import clsx from "clsx";

const Link = ({ isActive, children }: { isActive: boolean, children: React.ReactNode }) => {
  return <a className={twMerge(clsx("text-lg text-grey-800", { "text-blue-500": isActive }))}>{children}</a>;
};

clsx的輸出現在將通過tailwind-merge進行處理。tailwind-merge將解析類字符串并進行淺層樣式定義合并。這意味著text-grey-800被替換為text-blue-500,從而確保元素能體現出新的條件樣式應用。

這種方法有助于確保在實現變體時不會發生任何樣式沖突。由于className屬性也經過了cn工具的處理,如果需要,可以輕松覆蓋任何樣式。但這也存在一個權衡之處。使用cn開啟了組件使用者臨時覆蓋樣式的可能性。這將使一定程度的責任轉移到代碼審查步驟上,以驗證cn沒有被濫用。另一方面,如果根本不需要啟用這種行為,可以修改組件僅使用clsx。

在分析Badge組件的實現時,可以發現一些與 SOLID 原則相關的模式:

  • 單一職責原則: Badge 組件專注于一個職責,即根據提供的變體渲染不同樣式的徽章,并將樣式管理委托給了 badgeVariants 對象。
  • 開放/封閉原則: 代碼符合開放/封閉原則,允許添加新的變體而無需修改現有代碼。可以輕松地將新的變體添加到 badgeVariants 定義中的變體對象中。但需要注意的是,由于 cn 的使用方式,組件使用者可以通過 className 屬性傳遞新的覆蓋樣式。這可能會使組件對修改開放。因此,在構建自己的組件庫時,需要決定是否應允許這種行為。
  • 依賴倒置原則: Badge 組件及其樣式是分別定義的。Badge 組件依賴于 badgeVariants 對象獲取樣式信息。這種分離提供了靈活性和更容易的維護,符合依賴倒置原則。
  • 一致性和可重用性: 代碼通過使用實用函數 cva 來根據變體管理和應用樣式來促進一致性。這種一致性可以使開發人員更容易理解和使用組件。此外,Badge 組件是可重用的,可以輕松地集成到應用的不同部分中。
  • 關注點分離: 樣式和渲染的關注點被分開。badgeVariants 對象處理樣式邏輯,而 Badge 組件負責渲染和應用樣式。

在分析了 Badge 組件的實現之后,我們對 shadcn/ui 的一般架構有了更詳細的了解。但這是一個純顯示級別的組件。下面來看看其他一些交互式組件。

shadcn/ui Switch

下面是 Switch 組件的具體實現:

import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"

import { cn } from "@/lib/utils"

const Switch = React.forwardRef<
  React.ElementRef<typeof SwitchPrimitives.Root>,
  React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
  <SwitchPrimitives.Root
    className={cn(
      "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
      className
    )}
    {...props}
    ref={ref}
  >
    <SwitchPrimitives.Thumb
      className={cn(
        "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
      )}
    />
  </SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName

export { Switch }

Switch 組件是用于在兩個選項之間進行選擇的交互式組件,與僅用于顯示的 Badge 組件不同。Switch 組件能夠響應用戶的操作并切換其狀態,為用戶提供即時的反饋。

用戶與開關的交互主要通過點擊實現。構建一個能夠響應指針事件的開關相對簡單,但要使其也能響應鍵盤輸入和屏幕閱讀器,實現起來就更為復雜。以下是開關組件的一些預期行為:

  • 當用戶使用 Tab 鍵在界面上移動時,Switch 應該能接收焦點。
  • 一旦獲得焦點,用戶按下 Enter 鍵將觸發開關狀態的切換。
  • 在使用屏幕閱讀器的情況下,Switch 應能向用戶清晰地傳達其當前狀態。

在代碼中,可以看到開關的實際結構是通過使用 <SwitchPrimitives.Root/> 和 <SwitchPrimitives.Thumb/> 復合組件構建而成。這些組件來自 RadixUI 無頭庫,包含了開關的預期行為的所有實現。通過 React.forwardRef 進行構建,使得組件能夠與傳入的 ref 綁定,這在需要跟蹤焦點狀態并與外部庫集成時非常有用。

值得注意的是,RadixUI 組件沒有提供任何樣式。因此,經過 cn 實用函數處理后,樣式直接應用于該組件的 className 屬性上。如有需要,還可以使用 cva 為組件創建變體。這種靈活的樣式管理方式使得開發者能夠根據項目需求進行定制化設計,提高用戶體驗。

小結

這里我們討論了 shadcn/ui 的一般架構,這種實現方式同樣應用在 shadcn/ui 的其它組件中。不過,某些組件的行為和實現會稍微復雜一些,比如:

  • Calendar
  • 使用 react-day-picker 作為無頭組件。
  • 使用 date-fns 作為日期時間格式化庫。
  • Table 和 DataTable
  • 使用 @tanstack/react-table 作為無頭表格庫。
  • Form
  • 使用 react-hook-form 作為表單和表單狀態管理庫的無頭組件。
  • shadcn/ui 提供了封裝表單邏輯的實用組件,可用于組裝表單的各個部分,包括輸入和錯誤消息。
  • 表單的模式驗證庫使用 zod。zod 返回的驗證錯誤被傳遞到 <FormMessage/> 組件,在表單輸入旁邊顯示錯誤信息。

shadcn/ui 在前端開發領域中引入了一種創新的范例。它倡導一種新的思維方式,即開發者可以擁有組件的實現權,而不僅僅是依賴于抽象化的第三方包。通過這種方式,開發者能夠僅暴露所需的元素,從而更好地控制組件的行為和外觀。

在應用設計系統時,shadcn/ui 鼓勵開發者跳出預先構建的組件庫所限制的固定 API 表面。相反,它鼓勵開發者構建自己的設計系統,并提供足夠良好的默認設置,以便開發者可以根據自己的需求進行自定義。這種靈活性使得開發者能夠更好地適應不同的項目需求,并在設計過程中擁有更大的自由度。

總結

Shadcn UI 為開發者提供了一種全新的體驗,與現有的組件庫相比,它如一陣清風般令人耳目一新。它不僅加快了開發速度,還為開發者提供了對組件的精細控制,使他們能夠創造出獨特且富有創意的用戶界面。

當然,沒有任何庫能滿足所有需求,但基于當前的行業趨勢,Shadcn UI 無疑已成為前端生態系統中的佼佼者。許多大型公司,如 Vercel,已經采納了這一解決方案。例如,Vercel 的 v0 應用利用 Shadcn UI、Tailwind CSS 等來生成 UI 代碼,這些代碼可供開發人員直接復制并粘貼到其項目中。

盡管 Shadcn UI 仍是一個相對較新的工具,但隨著時間的推移,期待看到其功能和組件的進一步豐富和完善。你是否會考慮在未來的項目中采用 Shadcn UI 呢?

責任編輯:姜華 來源: 前端充電寶
相關推薦

2024-01-05 08:37:41

前端項目開發

2016-01-04 08:52:11

2024-03-05 10:32:16

2024-02-07 11:34:52

Preact前端庫React

2024-02-23 09:02:21

前端開源項目

2013-01-04 16:25:48

IT職位架構師

2013-09-12 15:51:56

2025-01-08 07:10:00

2018-02-06 12:48:12

人工智能深度學習AI芯片

2017-10-09 10:42:28

開源HTMLCSS

2014-10-10 13:46:33

Docker

2015-12-28 11:09:17

React Nativ前端

2015-12-28 10:56:10

react nativ前端

2014-08-27 09:45:30

JavaScriptJavaScript

2025-08-15 10:31:56

2013-05-30 10:31:03

Android開發移動開發Android開源項目

2012-10-29 14:18:58

開源云計算

2013-07-05 10:59:02

GitHub

2017-06-06 16:30:55

戴爾交付保障
點贊
收藏

51CTO技術棧公眾號

香港日本韩国三级网站| 国产精品视频一区二区三区经| 精品无码人妻一区| 韩日一区二区| 亚洲女同一区二区| 久久久免费看| 夜夜嗨aⅴ一区二区三区| 欧美不卡视频| 亚洲欧洲在线看| www.欧美激情.com| 激情视频网站在线播放色| 欧美国产精品v| 岛国一区二区三区高清视频| 国产寡妇亲子伦一区二区三区四区| 日韩电影免费网站| 亚洲第一视频在线观看| 一区二区xxx| 波多野结依一区| 国产精品久久精品日日| 国产综合精品一区二区三区| 中文字幕激情视频| 国产综合网站| 日韩视频在线免费| 国产精品揄拍100视频| 国产精品一区二区三区www| 日韩欧美中文字幕在线播放| 欧美一级黄色录像片| 免费理论片在线观看播放老| 国产成人无遮挡在线视频| 国产精品吊钟奶在线| 久久久久久久伊人| 91高清一区| 伊人av综合网| 日韩精品卡通动漫网站| 9999久久久久| 欧美一区二区三区四区视频| 黄色一级二级三级| 美女一区网站| 婷婷久久综合九色国产成人| 超级碰在线观看| 日本视频在线免费观看| 久久久精品黄色| 精品一卡二卡三卡四卡日本乱码 | 国产91久久精品一区二区| 欧美哺乳videos| 天天做天天干天天操| jvid一区二区三区| 日本精品视频一区二区三区| av之家在线观看| 黄色视屏在线免费观看| 亚洲国产一区在线观看| 777久久精品一区二区三区无码| 一本一道波多野毛片中文在线 | 波多野结衣家庭教师在线观看 | 久久黄色小视频| 一区二区三区在线观看免费| 不卡av电影在线观看| 潮喷失禁大喷水aⅴ无码| 欧洲杯什么时候开赛| 亚洲人成亚洲人成在线观看| theav精尽人亡av| 日韩高清三区| 亚洲乱码一区二区| 亚洲av综合一区二区| 精品在线99| 在线免费看av不卡| 女性裸体视频网站| 亚洲草久电影| 色综合久久久久久中文网| 精品爆乳一区二区三区无码av| 欧美理论在线| 午夜剧场成人观在线视频免费观看| 久久精品国产亚洲av麻豆色欲| 欧美精品一线| 欧美在线视频观看免费网站| 青青视频在线免费观看| 免费观看在线综合色| 91免费看国产| 欧美自拍第一页| 91麻豆免费看| 三区精品视频| av软件在线观看| 亚洲成人av免费| 国产综合免费视频| www.久久草.com| 精品999久久久| 国产免费一区二区三区网站免费| 日韩一区二区中文| 欧美激情影音先锋| 91午夜精品亚洲一区二区三区| 蜜桃av一区二区| 999在线免费观看视频| 亚洲aⅴ乱码精品成人区| 国产婷婷色一区二区三区在线| 亚洲资源在线网| av网站在线免费看推荐| 天天免费综合色| 一级片视频免费观看| 影音先锋欧美激情| 永久555www成人免费| h色网站在线观看| 亚洲欧美日韩专区| 91精品在线影院| 三级毛片在线免费看| 国产精品传媒视频| jizzjizz国产精品喷水| avtt久久| 国产亚洲日本欧美韩国| 久热精品在线观看| 日韩va亚洲va欧美va久久| 成人国产一区二区| 中文字幕日本在线| 狠狠久久五月精品中文字幕| 91日韩精品视频| 亚洲三级精品| 久久久久久久久久久网站| www.久久网| 99国产精品久久| 国产高清不卡无码视频| 成人日韩av| 国产视频精品自拍| 国产性生活网站| 国产综合色精品一区二区三区| 久久青青草综合| 日韩123区| 欧美三级中文字| 亚洲av综合一区二区| 亚洲小说区图片区| 亚洲精品日韩激情在线电影| av在线免费播放网站| 欧美日韩亚洲一区二| 日本美女视频网站| 综合色一区二区| 国产欧美一区二区三区在线看| 日色在线视频| 婷婷六月综合网| 亚洲中文字幕无码一区| 欧美日韩午夜| 亚洲精品欧美日韩专区| 免费黄网在线观看| 欧美日本国产视频| 色www亚洲国产阿娇yao| 日韩av高清在线观看| 欧美一级日本a级v片| 激情aⅴ欧美一区二区欲海潮| 欧美成人精品3d动漫h| 看免费黄色录像| 精东粉嫩av免费一区二区三区| 日韩一本精品| 欧美大片1688网站| 中文字幕亚洲综合久久| 性高潮视频在线观看| 国产日韩精品一区二区三区| 欧美私人情侣网站| 神马影视一区二区| 国产精品观看在线亚洲人成网| 九色在线免费| 在线精品视频免费观看| 手机毛片在线观看| 美日韩一级片在线观看| 一区二区三区国产福利| 日韩国产一二三区| 欧美成人免费全部| 人妻丰满熟妇av无码区hd| 亚洲成人激情综合网| 国产精品久久久免费观看| 免费看的黄色欧美网站| 日本中文不卡| www.久久爱.com| 欧美日韩成人在线视频| 欧洲成人一区二区三区| 欧美午夜精品久久久久久浪潮 | 欧美高清在线观看| 免费国产羞羞网站视频| 色婷婷综合久久久久中文 | 中文在线一区二区| 成人黄色一级大片| 亚洲午夜精品久久久久久app| 国外成人在线视频网站| 日韩电影大全网站| 久久国产一区二区三区| 亚洲男人第一天堂| 一本在线高清不卡dvd| 永久免费未视频| 粉嫩一区二区三区在线看| 日韩在线视频在线观看| 日韩专区精品| 91亚洲精品丁香在线观看| 麻豆理论在线观看| 在线观看国产精品淫| 亚洲xxx在线| 在线视频国内一区二区| 免费无遮挡无码永久在线观看视频| 99re66热这里只有精品3直播| 国产视频一区二区视频| 欧美激情日韩| 日韩福利在线| 综合激情五月婷婷| 日本三级久久久| 四虎亚洲精品| 一区二区成人精品| 欧美一级视频免费| 欧美巨大另类极品videosbest| 成年人免费看毛片| ...av二区三区久久精品| 亚洲制服丝袜在线播放| 国产在线精品不卡| 能在线观看的av网站| 欧美日韩一视频区二区| 色综合久久88色综合天天提莫| 亚洲午夜精品| 国产精品久久久久久久午夜 | 精品国产乱码久久久久久果冻传媒 | 久草精品电影| 警花av一区二区三区| 国产精品扒开腿做| 成人免费图片免费观看| 久久亚洲春色中文字幕| 国产精品视频一区二区久久| 亚洲成人国产精品| 国产又黄又爽视频| 欧美性xxxxx极品少妇| 国产精彩视频在线| 亚洲精品免费一二三区| 99热在线观看精品| 国产亚洲人成网站| 少妇户外露出[11p]| 国产成人免费在线观看不卡| jizzzz日本| 日日夜夜精品视频天天综合网| 每日在线更新av| 18成人免费观看视频| 300部国产真实乱| 亚洲国产成人精品女人| 亚洲欧洲一区二区| 成人黄色av| 无码免费一区二区三区免费播放 | 日本一区二区三区精品视频| 日韩精品社区| 精品欧美国产一区二区三区不卡| 伊人久久亚洲| 国产成人精品免费视频大全最热| 激情视频亚洲| 亚洲伊人第一页| 国产美女精品视频免费播放软件| 成人国产精品av| 国产成人视屏| 91在线精品观看| 2020国产精品极品色在线观看| 97超碰人人看人人| 视频在线亚洲| 国产精品99久久久久久久 | 精品少妇一区二区三区视频免付费 | 婷婷在线视频| 久久久www成人免费精品| 麻豆网在线观看| 欧美成人免费在线观看| 中文字幕伦理免费在线视频| 精品视频9999| 丰满诱人av在线播放| 97国产精品视频人人做人人爱| аⅴ资源天堂资源库在线| 97久久国产精品| 英国三级经典在线观看| 国产精品狠色婷| 免费成人黄色网| 亚洲精品欧美日韩| 国内精品国产成人国产三级粉色| 国产精品一区二区三区免费观看| 奇米影视777在线欧美电影观看| 久久99九九| 成人精品天堂一区二区三区| 波多野结衣三级在线| 欧美在线免费| 日韩欧美精品在线观看视频| 日韩成人精品在线观看| 九九九久久久久久久| 成人小视频免费观看| 亚洲天堂视频一区| 亚洲同性gay激情无套| 久久亚洲成人av| 欧美日韩一区二区三区| 一区二区久久精品66国产精品| 日韩精品一区二区三区四区| 日本大片在线观看| 久久精品美女视频网站| 成人bbav| 成人高清视频观看www| 欧美日韩一本| 伊人狠狠色丁香综合尤物| 亚洲国产91| 欧美三级理论片| 国产成人免费在线视频| 国产精品20p| 亚洲一区二区三区四区在线免费观看 | 91精品国产免费久久久久久| 免费污视频在线一区| 超碰在线97av| 日韩国产一区二区| av无码久久久久久不卡网站| 日本不卡在线视频| 荫蒂被男人添免费视频| 中文字幕亚洲一区二区va在线| 国产无遮挡免费视频| 欧美日韩成人一区二区| 视频一区二区在线播放| 久久福利网址导航| 香蕉成人影院| 久久国产精品一区二区三区| 亚洲精品久久久| 男女爽爽爽视频| 99国产麻豆精品| 久久午夜无码鲁丝片午夜精品| 欧美三级日韩三级| 日韩欧美在线番号| 欧美精品999| 91精品网站在线观看| 欧美性xxxx69| 亚洲青涩在线| 青青草精品在线| 国产精品久久久久影院色老大 | 中文字幕一区二区人妻在线不卡| 综合久久一区二区三区| 99久久久无码国产精品免费蜜柚| 精品国产免费一区二区三区四区 | 欧美激情亚洲一区| 日韩一区中文| 日韩欧美亚洲在线| 久久一本综合频道| 亚洲啪av永久无码精品放毛片| 最新中文字幕一区二区三区| 瑟瑟视频在线免费观看| 日韩精品中文字幕在线播放| 成人三级小说| 99国产视频| 午夜国产精品视频免费体验区| 欧美三级午夜理伦三级富婆| 欧美激情一区在线| 无码人妻丰满熟妇精品| 亚洲精品一区二区三区婷婷月| 18video性欧美19sex高清| 国产91视觉| 亚洲黄色大片| 艳妇乳肉豪妇荡乳xxx| 一区二区三区91| 亚洲乱码国产乱码精品精软件| 欧美成人激情视频免费观看| 成人在线视频国产| 中文字幕一区二区三区四区五区人| 九九精品视频在线看| 日韩在线观看免| 欧美一区二区日韩| v天堂福利视频在线观看| 91系列在线播放| 欧美在线看片| 91视频在线免费| 天天色图综合网| 欧美成熟毛茸茸| 日韩美女中文字幕| 成人精品天堂一区二区三区| 看看黄色一级片| 亚洲日本成人在线观看| 国产wwwxxx| 久久久在线视频| 天美av一区二区三区久久| 国产真实乱子伦| 国产精品视频九色porn| 亚洲一区二区视频在线播放| 久久久精品一区二区| 一区二区网站| 欧美激情 国产精品| 久久精品免费在线观看| 伊人免费在线观看| 欧美成人在线影院| 全国精品免费看| jizz欧美激情18| 亚洲另类在线一区| 天天插天天干天天操| 日本成人在线视频网址| 久久视频在线| 日本精品一二三区| 欧美性高潮床叫视频| 午夜伦全在线观看| 国产91aaa| 日韩综合小视频| 青草影院在线观看| 日韩禁在线播放| 看片一区二区| 蜜桃传媒一区二区三区| 国产视频一区二区在线| 99热这里只有精品在线观看| 69视频在线播放| 四季av一区二区凹凸精品| 亚洲一区二区三区四区av| 91黄色在线观看| 日韩成人伦理| 亚洲va久久久噜噜噜久久狠狠| 国产精品亚洲人在线观看| 在线免费观看国产精品| 欧美激情免费视频|