Skip to content

用 Vite 与原生 CSS 搭建轻量 React 看板界面 ​

译注:本文翻译自 dev.to 前端板块文章《Structuring a Lightweight React Kanban UI (Vanilla CSS & Vite)》,作者 Dhruv。原文链接见文末。文章以一个销售管道看板原型为例,讨论在不引入重型 UI 组件库的前提下,如何用 React、Vite 与原生 CSS 组织前端结构。

在构建内部工具或仪表盘原型时,人们很容易第一时间就安装 Material-UI、Ant Design 这类重型组件库。这些库确实功能强大,但对于许多早期原型来说,采用 Vite、React 加原生 CSS 的轻量方案,往往更容易定制、也更好维护。

本文以一个浅色主题的 CRM 仪表盘为例,梳理其前端架构。该界面采用看板式的销售管道布局。

技术范围 ​

在看代码之前,先明确这个示例到底包含什么。

它是什么:

  • 一个静态的前端 UI 原型
  • 一个用 Vite 构建的 React 应用
  • 一个响应式的看板式布局
  • 静态的模拟 CRM 数据
  • 原生 CSS 样式
  • 用 React 的 useState 实现的基础菜单状态

它不是什么:

  • 一个生产级 CRM
  • 一个后端应用
  • 一个连接数据库的系统
  • 一个集成 API 的应用
  • 一个鉴权系统
  • 一个支持拖拽的看板

这里的目标很简单:展示如何用 React 和标准 CSS 组织出一个干净的 CRM 风格前端。

React 组件 ​

这样的仪表盘可以拆成两个主要区域:

  1. 用于导航的侧边栏
  2. 包含销售管道的主内容区

在这个原型中,我们用 React 的 useState hook 来在视觉上跟踪当前激活的导航项。管道本身使用静态模拟数据。

jsx
import { useState } from 'react';
import './index.css';

function App() {
  const [activeMenu, setActiveMenu] = useState('pipeline');

  const leads = {
    new: [
      {
        id: 1,
        name: 'Acme Corp',
        value: '$5,000'
      }
    ],

    contacted: [
      {
        id: 3,
        name: 'Wayne Ent',
        value: '$8,200'
      }
    ],

    qualified: [
      {
        id: 5,
        name: 'Oscorp',
        value: '$25,000'
      }
    ],

    won: [
      {
        id: 6,
        name: 'Globex',
        value: '$14,000'
      }
    ]
  };

  return (
    <div className="crm-app">

      {/* Sidebar Navigation */}
      <aside className="sidebar-light">

        <div className="brand">
          <h1>LeadFlow CRM</h1>
        </div>

        <nav className="nav-menu">

          <button
            className={
              activeMenu === 'dashboard'
                ? 'active'
                : ''
            }
            onClick={() =>
              setActiveMenu('dashboard')
            }
          >
            Dashboard
          </button>

          <button
            className={
              activeMenu === 'pipeline'
                ? 'active'
                : ''
            }
            onClick={() =>
              setActiveMenu('pipeline')
            }
          >
            Sales Pipeline
          </button>

        </nav>

      </aside>

      {/* Main Content */}

      <main className="main-board">

        <header className="board-header">

          <h2>Sales Pipeline</h2>

          <button className="btn-primary">
            + New Deal
          </button>

        </header>

        {/* Kanban Board */}

        <div className="kanban-board">

          <div className="kanban-column">

            <h3>New Leads</h3>

            {leads.new.map((lead) => (

              <div
                className="kanban-card"
                key={lead.id}
              >

                <h4>{lead.name}</h4>

                <span className="value">
                  {lead.value}
                </span>

              </div>

            ))}

          </div>

          {/* Additional columns can be rendered here */}

        </div>

      </main>

    </div>
  );
}

export default App;

CSS 布局 ​

主布局可以完全用 CSS Flexbox 处理。根容器设为 flex 布局,让侧边栏和主仪表盘并排排列。

css
.crm-app {
  display: flex;
  height: 100vh;
  overflow: hidden;
  background-color: #f8fafc;
  color: #0f172a;
}

侧边栏 ​

侧边栏使用固定宽度,当主仪表盘扩展时它不会被压缩。

css
.sidebar-light {
  width: 260px;
  background-color: #ffffff;
  border-right: 1px solid #e2e8f0;

  display: flex;
  flex-direction: column;

  flex-shrink: 0;
}

这样可以让导航在视觉上保持稳定,同时主仪表盘内容保持弹性。

主仪表盘区域 ​

主内容区占据剩余的屏幕空间。

css
.main-board {
  flex-grow: 1;

  display: flex;
  flex-direction: column;

  overflow-x: auto;
}

横向看板布局 ​

看板本身也是一个 flex 容器。每一列都有固定的最小宽度,这样当列数增加时,看板可以横向滚动。

css
.kanban-board {
  display: flex;

  padding: 32px;

  gap: 24px;

  overflow-x: auto;

  flex-grow: 1;

  align-items: flex-start;
}

单个看板列 ​

每个管道阶段由一个简单的列表示。

css
.kanban-column {
  min-width: 280px;
  width: 280px;

  background-color: #f1f5f9;

  border-radius: 12px;

  padding: 16px;

  display: flex;
  flex-direction: column;

  gap: 16px;
}

列中的卡片随后可以展示这些信息:

  • 公司名称
  • 交易金额
  • 状态
  • 联系人信息
  • 销售阶段

在这个原型中,数据是刻意保持静态的。

响应式行为 ​

一个简单的媒体查询就能让布局适配更小的屏幕。例如:

css
@media (max-width: 768px) {

  .crm-app {
    flex-direction: column;
  }

  .sidebar-light {
    width: 100%;
  }

  .kanban-board {
    padding: 16px;
    overflow-x: auto;
  }
}

这样可以把侧边栏移到仪表盘上方,并让看板在较小屏幕上保持横向可滚动。

这种方案的价值 ​

1. 配置简单 ​

这个原型不需要额外的 UI 组件库,配置因此保持简单,样式也完全由你直接掌控。

2. 开发流程快 ​

Vite 提供了快速的开发体验,对典型前端项目而言,启动快、热模块替换也快。

3. 完全掌控样式 ​

使用原生 CSS 意味着你可以掌控:

  • 间距
  • 字体排版
  • 颜色
  • 边框
  • 阴影
  • 响应式行为

而无需去覆盖某个组件库既有的设计系统。

4. 组件结构清晰 ​

React 让仪表盘可以轻松拆成可复用的部分,例如:

  • 侧边栏
  • 头部
  • 看板列
  • 交易卡片
  • 指标卡片
  • 表格
  • 表单

随着原型成长,这些部分可以拆分为独立组件。

重要限制 ​

这个示例刻意只限于前端 UI 结构。它不包含:

  • API 请求
  • 鉴权
  • 数据库存储
  • 拖拽行为
  • 真实 CRM 数据
  • 后端业务逻辑

这些功能需要在这个轻量前端原型之外做进一步开发。

最终结果 ​

只使用:

  • React
  • Vite
  • 原生 CSS
  • 静态模拟数据

你就可以构建出一个干净、响应式的 CRM 风格仪表盘原型,而不必立刻引入大型 UI 库或后端基础设施。当你需要验证界面、构建内部工具原型,或把现有线框图变成可用的前端时,这种方案会很有用。

原文链接 ​