# Fonrey 组件规范设计文档 > **版本**:v1.0 · **日期**:2026-04-25 > **依赖基准**:`UI_SYSTEM.md v1.1` > **技术栈**:Tailwind CSS + HTMX + Alpine.js + Django 模板(非 JSX) > **设计语言**:专业克制高密度;主色 Teal `#0F766E`;圆角 `rounded-lg`(8px);桌面优先 ≥1280px --- ## 目录 1. [Data Table — 可排序多选数据表格](#1-data-table) 2. [Pagination — 分页组件](#2-pagination) 3. [Column Visibility Panel — 自定义列显示](#3-column-visibility-panel) 4. [Toolbar — 操作工具栏](#4-toolbar) 5. [Export Button — 导出按钮](#5-export-button) 6. [Smart Sort — 智能排序切换](#6-smart-sort) 7. [Modal Dialog — 模态对话框](#7-modal-dialog) 8. [Tree Select — 树形下拉选择器](#8-tree-select) 9. [Date Range Picker — 日期范围选择器](#9-date-range-picker) 10. [Tab Navigation — 标签页导航](#10-tab-navigation) 11. [Collapsible Card Grid — 可折叠卡片网格](#11-collapsible-card-grid) 12. [Photo Gallery Manager — 相册管理器](#12-photo-gallery-manager) 13. [Image Lightbox Viewer — 全屏图片灯箱](#13-image-lightbox-viewer) 14. [Accordion Progress Panel — 折叠进度检查面板](#14-accordion-progress-panel) 15. [Inline Edit Mode — 页面级读写切换](#15-inline-edit-mode) 16. [Drawer / Slide-over Panel — 右侧抽屉面板](#16-drawer--slide-over-panel) 17. [Multi-select Tag Input — 多选标签选择器](#17-multi-select-tag-input) 18. [Dynamic Form Table — 动态可增删行表格](#18-dynamic-form-table) 19. [Sortable Table with Drag Handle — 带拖拽手柄排序表格](#19-sortable-table-with-drag-handle) 20. [Multi-Table Independent Pagination — 同页多表格独立分页](#20-multi-table-independent-pagination) --- ## 1. Data Table **正式名称**:Sortable Data Table with Column Visibility Control ### 1.1 视觉规格 | 属性 | 值 | |---|---| | 行高 | 56px(`h-14`) | | 表头背景 | `bg-neutral-50` | | 表头文字 | `text-xs font-semibold text-neutral-500 uppercase tracking-wide` | | 行分割线 | `divide-y divide-neutral-100` | | 悬停行 | `hover:bg-neutral-50` | | 选中行高亮 | `bg-primary-50` | | 圆角容器 | `rounded-lg border border-neutral-200 overflow-hidden` | ### 1.2 子特性规范 | 子特性 | Token / 类名 | 说明 | |---|---|---| | 排序箭头(未排序) | `text-neutral-300` chevron-up-down icon | 双向箭头,`w-4 h-4` | | 排序箭头(升序激活) | `text-primary-600` chevron-up icon | 单向箭头 | | 排序箭头(降序激活) | `text-primary-600` chevron-down icon | 单向箭头 | | Checkbox 多选 | `w-4 h-4 rounded accent-primary-600` | Alpine.js 管理 `selected[]` 数组 | | 状态 Tag(出售) | `bg-primary-50 text-primary-700 text-xs px-2 py-0.5 rounded-full` | | | 状态 Tag(出租) | `bg-info-50 text-info-600 text-xs px-2 py-0.5 rounded-full` | | | 状态 Tag(待核验) | `bg-warning-50 text-warning-600 text-xs px-2 py-0.5 rounded-full` | | | 状态 Tag(已下架) | `bg-neutral-100 text-neutral-500 text-xs px-2 py-0.5 rounded-full` | | | 价格趋势箭头(上涨) | `text-success-600` arrow-up icon `w-3 h-3` | Alpine.js 条件渲染 | | 价格趋势箭头(下跌) | `text-danger-600` arrow-down icon `w-3 h-3` | | | 横向滚动 | `overflow-x-auto` 包裹 `` | 配合列 `min-w-[120px]` | ### 1.3 HTML 结构 ```html
房源标题 状态
``` ### 1.4 Alpine.js 数据结构 ```javascript function dataTable() { return { rows: [], // 由 Django 后端渲染 JSON 或 HTMX 注入 selected: [], // 选中行 ID 数组 sortKey: '', sortDir: 'asc', get allSelected() { return this.rows.length > 0 && this.selected.length === this.rows.length }, toggleAll(checked) { this.selected = checked ? this.rows.map(r => r.id) : [] }, sort(key) { if (this.sortKey === key) { this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc' } else { this.sortKey = key this.sortDir = 'asc' } // 触发 HTMX 请求,携带排序参数 htmx.trigger('#table-container', 'sort-change', { key: this.sortKey, dir: this.sortDir }) } } } ``` ### 1.5 HTMX 排序集成 ```html
``` --- ## 2. Pagination ### 2.1 视觉规格 | 属性 | 值 | |---|---| | 容器布局 | `flex items-center justify-between px-4 py-3 border-t border-neutral-200` | | 总条数文字 | `text-sm text-neutral-500` | | 页码按钮尺寸 | `w-8 h-8` `rounded-md` `text-sm` | | 当前页 | `bg-primary-600 text-white font-medium` | | 普通页码 | `text-neutral-600 hover:bg-neutral-100` | | 禁用状态 | `opacity-40 cursor-not-allowed` | | 省略号 | `text-neutral-400 px-1` | ### 2.2 HTML 结构 ```html
{{ paginator.count }}
{% for size in [10, 20, 50, 100] %} {% endfor %}
跳至
``` ### 2.3 Django 后端辅助函数 ```python def get_page_range(page_obj, on_each_side=2, on_ends=1): """生成含省略号的页码列表,供模板渲染""" paginator = page_obj.paginator current = page_obj.number total = paginator.num_pages result = [] left = set(range(1, on_ends + 1)) right = set(range(total - on_ends + 1, total + 1)) middle = set(range(current - on_each_side, current + on_each_side + 1)) visible = sorted(left | right | middle) prev = None for num in visible: if 1 <= num <= total: if prev and num - prev > 1: result.append('…') result.append(num) prev = num return result ``` --- ## 3. Column Visibility Panel ### 3.1 视觉规格 | 属性 | 值 | |---|---| | 触发按钮 | Secondary 按钮,`adjustments-horizontal` 图标 | | 面板宽度 | `w-64` | | 面板位置 | 右对齐弹出,`absolute right-0 top-full mt-1` | | 面板层级 | `z-20` | | 列项高度 | `h-9` | | Checkbox 颜色 | `accent-primary-600` | ### 3.2 HTML 结构 ```html
显示列
``` ### 3.3 Alpine.js 数据结构 ```javascript function columnVisibility() { const STORAGE_KEY = 'fonrey:table:property:cols' return { open: false, columns: [ { key: 'checkbox', label: '多选', visible: true, locked: true }, { key: 'code', label: '房源编号', visible: true, locked: true }, { key: 'title', label: '房源标题', visible: true, locked: false }, { key: 'status', label: '状态', visible: true, locked: false }, { key: 'price', label: '价格', visible: true, locked: false }, { key: 'area', label: '面积', visible: true, locked: false }, { key: 'district', label: '商圈', visible: false, locked: false }, { key: 'agent', label: '经纪人', visible: true, locked: false }, { key: 'created', label: '录入时间', visible: false, locked: false }, ], init() { const saved = localStorage.getItem(STORAGE_KEY) if (saved) { const savedCols = JSON.parse(saved) this.columns = this.columns.map(col => { const s = savedCols.find(c => c.key === col.key) return s ? { ...col, visible: s.visible } : col }) } }, savePreferences() { localStorage.setItem(STORAGE_KEY, JSON.stringify(this.columns.map(c => ({ key: c.key, visible: c.visible }))) ) }, resetToDefault() { localStorage.removeItem(STORAGE_KEY) this.columns.forEach(col => { if (!col.locked) col.visible = true }) } } } ``` --- ## 4. Toolbar ### 4.1 视觉规格 | 属性 | 值 | |---|---| | 容器 | `flex items-center gap-2 py-2` | | 批量按钮(未选中) | `opacity-50 cursor-not-allowed pointer-events-none` | | 批量按钮(已选中) | Secondary 按钮正常态 | | 选中计数 badge | `bg-primary-600 text-white text-xs px-1.5 py-0.5 rounded-full min-w-[20px] text-center` | | "更多"下拉 | `w-40` Dropdown,`ellipsis-horizontal` 图标 | ### 4.2 HTML 结构 ```html
{{ total_count }}
``` --- ## 5. Export Button ### 5.1 两种模式 | 模式 | 触发条件 | 实现方式 | |---|---|---| | 同步导出 | 数据量 ≤5000 条 | Django 视图直接返回 `FileResponse`,浏览器触发下载 | | 异步导出 | 数据量 >5000 条 | Celery 任务异步生成,完成后推送 Toast 通知(含下载链接) | ### 5.2 HTML 结构 ```html 导出 ``` --- ## 6. Smart Sort ### 6.1 视觉规格 | 状态 | 样式 | |---|---| | 未激活 | `border border-neutral-200 text-neutral-600 bg-white` | | 激活 | `border border-primary-600 text-primary-600 bg-primary-50` | ### 6.2 HTML 结构 ```html
``` --- ## 7. Modal Dialog ### 7.1 视觉规格 | 属性 | 值 | |---|---| | 遮罩 | `fixed inset-0 bg-black/50 z-40` | | 面板宽度 | `w-full max-w-lg`(默认)/ `max-w-2xl`(宽型) | | 面板圆角 | `rounded-xl` | | 面板阴影 | `shadow-2xl` | | Header 高度 | `h-14`,`border-b border-neutral-200` | | Footer 高度 | `h-16`,`border-t border-neutral-200` | | 拖拽手柄 | `cursor-grab active:cursor-grabbing text-neutral-300 hover:text-neutral-500` | ### 7.2 HTML 结构 ```html
``` ### 7.3 Alpine.js 数据结构 ```javascript function modal() { return { isOpen: false, reason: '', open() { this.isOpen = true }, close() { this.isOpen = false; this.reason = '' } } } ``` --- ## 8. Tree Select ### 8.1 视觉规格 | 属性 | 值 | |---|---| | 触发框 | `h-9 px-3 text-sm border border-neutral-200 rounded-md` | | 面板宽度 | `w-72` | | 父节点行高 | `h-9` | | 子节点行高 | `h-9 pl-8`(左缩进) | | 展开箭头 | `w-4 h-4 transition-transform`,展开时 `rotate-90` | | 已选节点 | `bg-primary-50 text-primary-700` | | 带头像叶节点 | `w-6 h-6 rounded-full bg-primary-100 text-primary-700 text-xs flex items-center justify-center` | | Badge(关闭状态) | `bg-warning-50 text-warning-600 text-xs px-1.5 py-0.5 rounded-full` | | 底部操作行 | `sticky bottom-0 border-t border-neutral-100 bg-white px-3 py-2` | ### 8.2 推荐实现方案 **方案一(默认,数据量 ≤200 节点)**:后端一次性返回完整 JSON,Alpine.js 前端递归渲染 **方案二(数据量大)**:HTMX 懒加载子节点(点击展开时 `hx-get` 请求子数据) ### 8.3 HTML 结构(方案一) ```html
暂无匹配结果
``` ### 8.4 Alpine.js 数据结构 ```javascript function treeSelect() { return { open: false, query: '', selected: null, hideInactive: false, tree: [], // 从 Django 后端注入:[{ id, label, badge, children: [{id, label, code}] }] get filteredTree() { if (!this.query) return this.tree const q = this.query.toLowerCase() return this.tree .map(group => ({ ...group, children: group.children.filter(leaf => leaf.label.includes(q) || leaf.code?.includes(q) ) })) .filter(group => group.children.length > 0) }, selectLeaf(leaf) { this.selected = leaf this.open = false this.query = '' } } } ``` --- ## 9. Date Range Picker ### 9.1 技术选型 **使用 Flatpickr**(CDN,~16KB,无框架依赖),不手写。 ```html ``` ### 9.2 初始化配置 ```javascript flatpickr('#dateRange', { mode: 'range', showMonths: 2, locale: 'zh', dateFormat: 'Y-m-d', allowInput: true, onReady(_sel, _str, fp) { fp.calendarContainer.classList.add('fonrey-calendar') } }) ``` ### 9.3 样式覆盖(配合主色 Teal) ```css /* static/css/flatpickr-overrides.css */ .flatpickr-day.selected, .flatpickr-day.startRange, .flatpickr-day.endRange { background: #0F766E; border-color: #0F766E; } .flatpickr-day.inRange { background: #CCFBF1; border-color: #CCFBF1; color: #115E59; } .flatpickr-day.today { border-color: #D97706; } ``` ### 9.4 HTML 结构 ```html
``` --- ## 10. Tab Navigation ### 10.1 视觉规格 | 属性 | 值 | |---|---| | Tab 容器 | `border-b border-neutral-200` | | Tab 按钮(未激活) | `h-10 px-4 text-sm text-neutral-500 hover:text-neutral-700` | | Tab 按钮(激活) | `h-10 px-4 text-sm text-primary-600 font-medium border-b-2 border-primary-600` | | 内容区顶部间距 | `mt-4` | ### 10.2 HTML 结构 ```html
``` ### 10.3 Timeline 子组件 ```html
{% for log in logs %}
{{ log.operator }} {{ log.action }} {{ log.created_at }}
{{ log.detail }}
{% endfor %}
{% if has_more %} {% endif %}
``` --- ## 11. Collapsible Card Grid ### 11.1 视觉规格 | 属性 | 值 | |---|---| | 外层卡片 | `bg-white rounded-lg border border-neutral-200` | | Section Header | `flex items-center justify-between px-4 py-3 border-b border-neutral-100` | | 网格列数 | `grid grid-cols-3 gap-4` | | 员工卡片 | `p-3 rounded-lg border border-neutral-100 hover:border-neutral-200` | | 头像尺寸 | `w-10 h-10 rounded-full` | | 展开按钮 | `w-full flex items-center justify-center h-9 text-sm text-neutral-500 hover:bg-neutral-50 border-t border-neutral-100` | ### 11.2 HTML 结构 ```html

相关员工

{% for member in members %}
{{ member.name }}
{{ member.name }}
{{ member.store }}
{{ member.phone }}
{{ member.role }}
{% endfor %} {% if members|length < 3 %}
暂未分配
{% endif %}
``` --- ## 12. Photo Gallery Manager ### 12.1 组件构成 | 子组件 | 实现方式 | |---|---| | Scrollable Tab Bar(分类标签) | Tailwind `overflow-x-auto flex` + Alpine.js 激活态 | | Image Grid with Checkbox | Tailwind `grid grid-cols-6 gap-2` + Alpine.js 多选 | | Batch Action Toolbar | Alpine.js `:disabled` 状态控制 | | Drag-and-Drop Upload | **Filepond**(CDN,~50KB) | | Drag-to-Reorder | **SortableJS**(CDN,~3KB) | ### 12.2 图片网格 HTML ```html
已选
``` ### 12.3 Filepond 上传初始化 ```javascript // static/js/filepond-init.js FilePond.registerPlugin(FilePondPluginImagePreview) FilePond.setOptions({ server: { process: '/api/photos/upload/', headers: { 'X-CSRFToken': getCookie('csrftoken') } }, labelIdle: '拖拽图片到此处,或 点击选择', acceptedFileTypes: ['image/*'], allowMultiple: true, maxFiles: 50, }) ``` --- ## 13. Image Lightbox Viewer ### 13.1 技术选型 **使用 Viewer.js**(CDN,~5KB,无框架依赖)覆盖缩放/旋转/全屏/翻页/缩略图条。 ```html ``` ### 13.2 初始化 ```javascript const gallery = document.getElementById('photo-gallery') const viewer = new Viewer(gallery, { toolbar: { zoomIn: true, zoomOut: true, oneToOne: true, reset: true, rotateLeft: true, rotateRight: true, download: true, }, navbar: true, title: (image) => `${image.alt} · ${image.naturalWidth} × ${image.naturalHeight}`, url: 'data-src', // 使用 data-src 存储原图 URL }) ``` ### 13.3 触发按钮集成 ```html ``` --- ## 14. Accordion Progress Panel ### 14.1 视觉规格 | 属性 | 值 | |---|---| | 进度条轨道 | `h-2 bg-neutral-100 rounded-full` | | 进度条填充(正常) | `bg-warning-600 rounded-full transition-all` | | 进度条填充(满分) | `bg-success-600` | | 父行(折叠头) | `flex justify-between items-center h-10 px-4 cursor-pointer hover:bg-neutral-50` | | 子行 | `flex justify-between items-center h-9 pl-8 pr-4 text-sm` | | 分数(正常) | `text-sm text-neutral-600 tabular-nums` | | 分数(0分/未达标) | `text-sm text-danger-600 font-medium tabular-nums` | | 操作链接 | `text-xs text-primary-600 hover:text-primary-700 ml-2` | ### 14.2 HTML 结构 ```html

信息完整度

69%

完善信息可提升房源曝光率。 了解更多

{% for group in progress_groups %} {% if group.is_collapsible %}
{% for item in group.items %}
{{ item.label }}
{{ item.score }}% / {{ item.max_score }}% {% if item.action %} {{ item.action }} {% endif %}
{% endfor %}
{% else %}
{{ group.label }}
{{ group.score }}% / {{ group.max_score }}% {% if group.action %} {{ group.action }} {% endif %}
{% endif %} {% endfor %}
``` > **注意**:需引入 Alpine.js 官方 `x-collapse` 插件(1KB)处理高度动画。 --- ## 15. Inline Edit Mode ### 15.1 视觉规格 | 状态 | 区分方式 | |---|---| | 只读态 | 纯文本 ``,无边框 | | 编辑态 | `` / `
自动生成员工编号
``` ### 15.3 Alpine.js 数据结构 ```javascript function inlineEdit() { return { editing: false, settings: {}, _snapshot: null, init() { // 从 Django 注入的 JSON 初始化 this.settings = JSON.parse(document.getElementById('settings-data').textContent) }, startEdit() { this._snapshot = JSON.parse(JSON.stringify(this.settings)) this.editing = true }, cancelEdit() { this.settings = JSON.parse(JSON.stringify(this._snapshot)) this.editing = false }, saveEdit() { this.editing = false }, getFormData() { return JSON.stringify(this.settings) } } } ``` --- ## 16. Drawer / Slide-over Panel ### 16.1 视觉规格 | 属性 | 值 | |---|---| | 遮罩 | `fixed inset-0 bg-black/30 z-40` | | 面板宽度(默认) | `w-[480px]` | | 面板宽度(宽型) | `w-[640px]` | | 面板层级 | `z-50` | | 入场动画 | `translate-x-full → translate-x-0`,`duration-300 ease-out` | | Header 高度 | `h-14 border-b border-neutral-200` | | Footer 高度 | `h-16 border-t border-neutral-200` | | 内容区 | `flex-1 overflow-y-auto` | ### 16.2 HTML 结构 ```html
``` > **注意**:需引入 Alpine.js 官方 `@alpinejs/focus` 插件以支持 `x-trap`(焦点锁定在 Drawer 内)。 --- ## 17. Multi-select Tag Input ### 17.1 视觉规格 | 属性 | 值 | |---|---| | 容器(默认) | `flex flex-wrap gap-1 min-h-[36px] px-2 py-1 border border-neutral-200 rounded-md` | | 容器(激活) | `+ ring-2 ring-primary-600/40 border-primary-400` | | Tag/Chip | `inline-flex items-center gap-1 bg-primary-50 text-primary-700 text-xs px-2 py-0.5 rounded-full` | | Tag 删除按钮 | `text-primary-400 hover:text-primary-700` | | 下拉选项(未选) | `px-3 h-9 text-sm text-neutral-700 hover:bg-neutral-50` | | 下拉选项(已选) | `+ bg-primary-50 text-primary-700` + `check` 图标 | ### 17.2 HTML 结构 ```html
暂无匹配选项
``` ### 17.3 Alpine.js 数据结构 ```javascript function multiSelectTag() { return { open: false, query: '', selected: [], options: ['出售', '出租', '租售', '他售/不售', '他租/不租', '暂缓'], get filteredOptions() { if (!this.query) return this.options return this.options.filter(o => o.includes(this.query)) }, toggle(option) { const i = this.selected.indexOf(option) i === -1 ? this.selected.push(option) : this.selected.splice(i, 1) }, isSelected(option) { return this.selected.includes(option) }, remove(option) { this.selected = this.selected.filter(s => s !== option) } } } ``` --- ## 18. Dynamic Form Table ### 18.1 视觉规格 | 属性 | 值 | |---|---| | 表格边框 | `border border-neutral-200 rounded-lg overflow-hidden` | | 表头 | `bg-neutral-50 text-xs font-semibold text-neutral-500 uppercase` | | 系统预置行 | 字段名称不可编辑,操作列显示 `-`(`text-neutral-400`) | | 用户自定义行 | 字段名称可编辑 ``,操作列显示"隐藏不使用" | | 必填 Badge(必填) | `bg-primary-600 text-white text-xs px-2 py-0.5 rounded-full` | | 必填 Badge(非必填) | `bg-neutral-200 text-neutral-500 text-xs px-2 py-0.5 rounded-full` | | Toggle 开关(主色) | `bg-primary-600`(开)/ `bg-neutral-300`(关) | | 添加行按钮 | `border-t border-dashed border-neutral-200 text-primary-600 hover:bg-primary-50` | ### 18.2 HTML 结构 ```html
字段名称 字段类型 可选内容 是否必填 操作
``` --- ## 19. Sortable Table with Drag Handle ### 19.1 技术选型 **SortableJS**(CDN,~3KB),与 Alpine.js 集成,处理拖拽排序。 ### 19.2 视觉规格 | 属性 | 值 | |---|---| | 拖拽手柄 | `cursor-grab active:cursor-grabbing text-neutral-300 hover:text-neutral-500` | | 拖拽中行 | `.sortable-chosen`:`bg-primary-50 shadow-md` | | 放置占位行 | `.sortable-ghost`:`border-2 border-dashed border-primary-300 bg-transparent opacity-50` | ### 19.3 HTML 结构 ```html
字段名称
``` ### 19.4 Alpine.js + SortableJS 初始化 ```javascript function sortableTable() { return { rows: [], initSort() { Sortable.create(document.getElementById('sortable-table'), { handle: '.drag-handle', animation: 150, chosenClass: 'bg-primary-50 shadow-md', ghostClass: 'sortable-ghost', onEnd: (evt) => { const moved = this.rows.splice(evt.oldIndex, 1)[0] this.rows.splice(evt.newIndex, 0, moved) this.saveOrder() } }) }, saveOrder() { fetch('/api/field-options/reorder/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ ids: this.rows.map(r => r.id) }) }) } } } ``` ```css /* Drop 占位行样式(在 static/css/app.css 中定义,不写 inline) */ .sortable-ghost { border: 2px dashed #5EEAD4; /* primary-300 */ background: transparent !important; opacity: 0.5; } ``` --- ## 20. Multi-Table Independent Pagination ### 20.1 核心设计原则 每个表格区块拥有**独立的三要素**,通过 HTMX `hx-target` 精准隔离: ``` 表格区块 N ├─ id="table-{module}" ← 唯一 DOM 目标 ├─ hx-target="#table-{module}" ← 分页只刷新自身 └─ /api/{module}/?page=N ← 独立后端分页接口 ``` 翻某个表格的页,其他表格 **DOM 完全不变**。 ### 20.2 HTML 结构 ```html

业客信息

买卖双方及关联人员信息字段

{% include "partials/table_customer.html" %}
{% include "partials/pagination.html" with target="#table-customer" url_base="/params/customer/" page_obj=customer_page %}

合同-应收费用

{% include "partials/table_fee.html" %}
{% include "partials/pagination.html" with target="#table-fee" url_base="/params/fee/" page_obj=fee_page %}
``` ### 20.3 分页器 Partial 模板(可复用) ```html {# templates/partials/pagination.html #} {# 参数:target(HTMX 目标)、url_base(接口基础 URL)、page_obj #} ``` --- ## 附录 A:第三方库清单 | 库 | 版本 | 用途 | 引入方式 | 使用组件 | |---|---|---|---|---| | Flatpickr | latest | 日期范围选择 | CDN | Date Range Picker | | SortableJS | latest | 拖拽排序 | CDN | Sortable Table、Photo Gallery | | Filepond + ImagePreview 插件 | latest | 图片上传 + 预览 | CDN | Photo Gallery Manager | | Viewer.js | latest | 图片灯箱预览 | CDN | Image Lightbox | | @alpinejs/collapse | latest | 折叠高度动画 | CDN | Accordion、Collapsible Card | | @alpinejs/focus | latest | 焦点锁定 | CDN | Modal、Drawer | > 以上库均为**无框架依赖**纯 JS 工具库,与 HTMX + Alpine.js + Tailwind 技术栈完全兼容。 --- ## 附录 B:组件难度分级 | 难度 | 组件 | |---|---| | ⭐ 简单(<30 行 JS) | Toggle Switch、Tab Navigation、Collapsible Card、Accordion Progress Panel、Toolbar | | ⭐⭐ 中等(30~80 行 JS) | Data Table、Pagination、Column Visibility Panel、Inline Edit Mode、Drawer、Multi-select Tag Input、Dynamic Form Table | | ⭐⭐⭐ 较难(需外部库或复杂数据结构) | Tree Select、Sortable Table、Photo Gallery Manager、Image Lightbox、Date Range Picker、Multi-Table Pagination | --- ## 附录 C:关联文档 - `UI_SYSTEM/UI_SYSTEM.md` — 设计 Token、颜色系统、基础组件规范(权威基准) - `UI_SYSTEM/组件清单.md` — 组件可行性分析与实现建议(本文源材料) - `TECH_STACK/TECH_STACK.md` — 技术选型总纲 - `PRD/*` — 各业务模块产品需求 --- *文档版本 v1.0 · 2026-04-25 · 基于 UI_SYSTEM.md v1.1 生成*