为啥就换Shadcn了
因为Shadcn太火了,不少大大小小的火出圈的ai项目,就是基于Shadcn搭建的,比如assistant-ui,为了与时俱进,与国际接轨,要求我必须整出来一套对接好Ruoyi-pro,支持KeepAlive的管理后台架子,准备稳步迭代部分旧有项目和开发新项目,主动迎接ai代码智能体的时代,为团队插上ai赋能翅膀
反正闲着也是闲着,那就整吧~
shadcn是真“一用一个不吱声”
看是该给的都给了,实则要啥没啥,简直“如给”
但不用慌,这回就到了体现React社区强大之处的时候了~
我想整个Tree,有么?
- 社区:rc-tree
- 需求:因为ruoyi中有几处需要tree的地方,比如用户管理
- 演示:
开发心得: 主要是定制上,demo的样式没法用,定制起来些许阻碍,不过好在都有办法解决,花了一天整合出了Shacn版本,可以为了道友们节省一些精力。
我想整个table,有么?
- 社区:tanstack table
- 需求:不用问了吧,必须得有的,而且还得支持折叠,选中,翻页等功能
- 演示:
开发心得:当开发折叠的时候,发现折叠打开的时候要,下方的数据会被挤到下一页的问题,一时不知怎么解决,翻了文档,居然真有解决办法,很轻松就解决了,从这一点就能看出来,这个库有多神,table是玩明白了,面面俱到。
我想整个表单,有么?
- 社区:react-hook-form
- 需求:不用问了吧,表单太关键了
- 演示:
我想整个toast,有么?
- 社区:sonner
- 需求:不用说了,基本需求
- 演示:
我想整个路由导航进度条,有么?
- 社区:bprogress
- 需求:Nextjs的路由跳转的时候,避免不了加载过程,有些时候网络比较慢,那么点击导航的时候看起来像没反应,体验不好,加个进度条,提示一下页面正在加载。
- 演示:
我想整个路由切换动画,有么?
- 社区:motion
- 需求:路由切换的时候,最好给个过渡动画,不然切换太突兀,观感不好,需要改善一下体验
- 演示:
我想整个icon,有么?
- 社区:iconify
- 需求:简单好用,海量icon,无需引入太多,仅传入一个icon字符即可。
- 演示:
keep alive
三步骤,一步一登梯
第一步:keepAlve, 第二步:tab导航,因为没有tab导航的keepalive就是吃酱牛肉不配蒜酱啊,没有灵魂,现实来看就是,你得让keepAlive有生命周期,光靠菜单,就会永远缓存,得可以关闭,tab栏就是给你管理keepAlive用的 第三步:useActive-可以监听切换窗口的hook,这步看似不起眼,但是实则才是能否完整keep alive的验金石
方案介绍
本方案为 Next.js 提供了灵活的页面缓存(KeepAlive)能力,适用于多标签页、页面状态保留等复杂场景。
主要文件说明
-
keep-alive:顶层组件,提供全局 KeepAlive 能力
-
keep-alive-sign:标记需要缓存的页面或组件
-
keep-alive-slot:定向渲染插槽,实现精准渲染
-
keep-alive-route:内部业务核心组成,通常无需关注
使用方法
第一步:在顶层 Layout 包裹 KeepAlive
在页面的 layout 组件(如管理后台 dashboard 的 layout.tsx)中包裹 KeepAlive:
<KeepAlive>{children}</KeepAlive>
第二步:在需要缓存的页面中使用 KeepAliveSign
// 客户端渲染,并且需要缓存的组件
const MenuView = () => {
return <div>菜单页面</div>;
};
export default function MenuPage() {
const customId = "自定义id";
return (
<div>
{/* 其他组件,可为服务端或客户端组件。key 用于复杂场景避免渲染错位 */}
<KeepAliveSign key={customId} routeId={customId} ClientView={MenuView}>
...
</KeepAliveSign>
</div>
);
}
-
routeId:路由唯一标识,必须唯一,用于标记缓存页面
-
key:唯一标识,建议复杂场景下使用,避免渲染错位
-
ClientView:需要被缓存的客户端组件
第三步:在 KeepAliveSign 内使用 KeepAliveSlot 实现定点渲染
与服务端组件组合渲染时,KeepAliveSlot 可实现精准定位:
export default function MenuPage() {
const customId = "自定义id";
return (
<div>
<KeepAliveSign key={customId} routeId={customId} ClientView={MenuView}>
{/* 其他组件,可为服务端或客户端组件 */}
<KeepAliveSlot id={customId} />
{/* 其他组件,可为服务端或客户端组件 */}
</KeepAliveSign>
</div>
);
}
- id:需与 KeepAliveSign 的 routeId 保持一致,无需设置不同值
Tab导航,拖拽,缓存
useActive
路由增强
Next.js 原生采用约定式、基于文件系统的路由机制。
那为什么还需要额外配置路由?
主要是为了满足更复杂的业务需求,例如:
-
支持 KeepAlive 页面缓存
-
多标签页(Tab)窗口
-
菜单权限控制
-
函数式路由跳转
-
自动补全路由 path,减少重复配置
-
以及其他路由元信息的灵活扩展
本方案通过配置化的数据结构和统一的 routerHelper 工具,将所有与路由相关的业务接口集中管理,极大简化了路由与接口的维护流程,提升了项目的可扩展性和长期可维护性。
主要文件说明
-
router-name:为每个路由分配唯一标识
-
routes-config:配置路由的基本信息
-
router-provider:增强路由能力,如自动补全 path、提供函数式跳转等
-
router-type:路由相关的类型定义
如何创建一个新路由
第一步:在 router-name.ts 中添加路由名称
export enum ROUTE_NAME {
// ... 其他路由名称
user,
}
第二步:在 routes-config.ts 中添加路由配置
import { ROUTE_NAME } from "./router-name";
import User from "@/pages/User"; // 假设你有一个User页面组件
const routesConfig = {
user: {
id: "user",
meta: {
title: "common:UserPageTitle",
icon: "FundProjectionScreenOutlined",
},
},
};
export default routesConfig;
第三步:路由跳转
可在全局任意位置通过函数方式跳转,组件外也能直接调用:
routerHelper.jumpTo(ROUTE_NAME.dashboard);
ruoyi对接
登录
角色管理
用户管理
菜单管理
为啥要用Shadcn,相比Antd,mui又如何?
这个问题太难回答了,我的观点是当下无脑选shadcn,因为最契合现在Ai代码智能体时代、
用过这三个组件库的我,怎么描述我对三个组件库的直观感受呢?em~~就像乐高
Antd
Mui
Shadcn
这三张图就是我对这三大组件库的感受,shadcn结合原子化样式+足够碎,使其有着更好的组合空间,天花板很高,并且结合ai,可以很容易生成出来我们想要的东西,
项目地址和预览地址
还有好多功能细节,玩法技巧,这里就不作赘述,有兴趣的朋友可以自行探索。
源码已经开源,java用的就是Ruoyi芋道作为后端例子,有兴趣的可以自行运行起来。
前端是一个Monorepo,放在了根目录下的frontend文件夹下,直接运行npm run start
即可运行。
技术支持
欢迎加入「闲 D 岛 🏝️」技术交流群,这里有大厂工程师、独立开发者、外包团队和热心小伙伴,氛围纯净,技术交流活跃,期待你的加入!
- 闲 D 岛 1 群(500+ 人):551406017
- 闲 D 岛 2 群:1002504812