为什么 shadcn ui 能杀入2023年前端工具库榜首

shadcn ui 介绍

无样式组件库 headless ui

在介绍 shadcn ui 之前,我们先来看前几年出现的概念: headless 组件库

你是否碰上这样的场景,使用 antd / element ui 组件库时,设计让你调整个组件样式(比如说日历日期的特殊颜色等)。

这种情况,通常要费很大的力气跟设计沟通,为什么我不能修改这里的样式,即使只是一小点改动。

组件库都是写好了的,而且底层是耦合的代码,这很难进行更改。强行更改的方案都很脏,不够优雅。

在这种情况下,headless 组件库横空出世。简单理解的话,它只写了逻辑代码,而没有样式代码,让我们看个 demo:

js 复制代码
import { useState } from 'react' 
import { Switch } from '@headlessui/react' 
function MyToggle() { 
    const [enabled, setEnabled] = useState(false) 
    return ( 
        <Switch 
            checked={enabled} 
            onChange={setEnabled} 
            style={{ 
                background-color: enabled ? 'blue' ? 'gray',
                position: 'relative',
                display: 'inline-flex',
                height: 6,
                width: 11,
                align-items: 'center',
            }}
        > 
            <span className="sr-only">Enable notifications</span> 
            <span
                style={{
                    display: 'inline-block',
                    height: 4,
                    width: 4,
                    backgroung: white
                }}
            /> 
        </Switch> 
    ) 
}

可以看到,小小一个开关,几乎所有的样式包括开启、关闭等状态的样式都要亲力亲为,手动实现,否则就是原生的样子。

这样做的好处是足够灵活,但坏处就是太麻烦了,要编写大量组件样式。另外 headless 只提供了 10 个组件,远远不够日常项目使用。

基于 headless 思想的组件库 radix ui

为了解决第二个组件不够的问题,又出现了许多基于 headless 封装的组件库。以 Radix UI 为例,它提供了数十个新的组件,已经能满足日常开发使用了。许多小公司自己的组件库 就是基于他们进行开发的,可以很方便的深入定制自己的样式而不用书写大量逻辑。

有了它们,只剩下样式很繁琐这个问题了,接下来有请主角 shadcn ui 登场

打破常规思路的 shadcn ui

如果是你,你会怎么解决上述样式亲力亲为的问题呢?

  1. 自己封装一个组件库供成员使用(发布组件很麻烦很费时)
  2. 做一个样式生成器,覆盖大部分组件(工作量不小,容易出冲突)
  3. 开摆

我能想到的方案都有一定的缺陷,这也是我之前不想用这个的原因,但是 shadcn 给出了自己天才般的设计:

  1. 组件库搬到本地,而且提供许多默认样式
  2. 集成 tailwindcss 大幅度简化样式
  3. 利用 class-variance-authority 进行分化定制
  4. 傻瓜都能看懂的干净代码,能轻松进行改造

DEMO 时间

你不需要安装任何库,而是直接将组件文件直接加入你的代码之中,也就是把源码下载到项目中!举个例子,你如果想使用 button 组件,那么首先使用命令加入:

cmd 复制代码
npx shadcn-ui@latest add button

你就会看到,你的代码中多出来一个文件:

这样就可以直接引用 button 组件了。由于代码足够清晰,可以很方便的使用 tailwindcss 对样式进行改造重写,同时可以使用 cva 进行分化定制,学习成本几乎为0。

这里使用了 class-variance-authority 工具来让逻辑更清晰,详情可以查看下文的工具库介绍

一些缺点

  1. 如果对于定制化要求不那么高,那么用 element、antd 那些开箱即用的组件库会更方便,毕竟这个需要花时间去适应。
  2. 同事可能会不通知你就改掉本地组件库,不要过分相信其他人的技术力。

shadcn 相关工具库

class-variance-authority

充分利用 tailwindcss,专注于样式封装,可以利用它来编写自己的组件库,例如:

js 复制代码
import { cva } from "class-variance-authority";
// 第一个参数是预置css,无论哪个分支都会有。variants 变体详情则需要自己定制不同的样式,变体包括意图主体 intent,大小等等
const button = cva(["font-semibold", "border", "rounded"], {
    variants: {
        intent: {
            primary: [ "bg-blue-500", "text-white", "border-transparent", "hover:bg-blue-600", ], 
            secondary: [ "bg-white", "text-gray-800", "border-gray-400", "hover:bg-gray-100", ], 
        },
        size: {
            small: ["text-sm", "py-1", "px-2"],
            medium: ["text-base", "py-2", "px-4"], 
        },
    }, 
    defaultVariants: { intent: "primary", size: "medium", },
});

之后就可以通过这种方式来获取到按钮

js 复制代码
button({ intent: "secondary", size: "small" }); // 输出一堆复合定制预期的 css

项目中具体使用

js 复制代码
// 是的,你仍然可以加 classname
className={ buttonVariants({ variant, size, className }) }

tailwind-merge

可以处理掉 tailwindcss 类名冲突的情况,优先级按照 tailwind 的进行,如

js 复制代码
className={ twMerge("w-10 w-20") } // 会合并为 w-20

clsx

classNames 的上位替代,使用率已经超过 classNames。足够小巧,贴一段官方代码

js 复制代码
import clsx from 'clsx';

clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'

clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'

clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });
//=> 'foo --foobar'

小插件

  • lucide-react:拥有 1k+ 图标的轻量图标库
  • embla-carousel-react:幻灯片插件
  • cmdk:命令插件
  • vaul:抽屉插件
  • react-hook-form:表单相关能力
  • react-resizable-panels:可动态调整的面板
  • next-themes:切换主题能力
  • sonner:小提示插件

工具库总结

自己开发的其实并不多,shadcn 基于 radix ui,大量集成了优质插件,可以说集百家所长了。如果遇到类似场景,也许能从这些源码里能知不少得到好用且前沿的工具库。

相关推荐
excel6 小时前
为什么在 Three.js 中平面能产生“起伏效果”?
前端
excel7 小时前
Node.js 断言与测试框架示例对比
前端
天蓝色的鱼鱼8 小时前
前端开发者的组件设计之痛:为什么我的组件总是难以维护?
前端·react.js
codingandsleeping8 小时前
使用orval自动拉取swagger文档并生成ts接口
前端·javascript
石金龙9 小时前
[译] Composition in CSS
前端·css
白水清风9 小时前
微前端学习记录(qiankun、wujie、micro-app)
前端·javascript·前端工程化
Ticnix10 小时前
函数封装实现Echarts多表渲染/叠加渲染
前端·echarts
用户221520442780010 小时前
new、原型和原型链浅析
前端·javascript
阿星做前端10 小时前
coze源码解读: space develop 页面
前端·javascript
叫我小窝吧10 小时前
Promise 的使用
前端·javascript