This commit is contained in:
wfz
2025-12-22 23:20:40 +08:00
parent ff8a6a28f8
commit 9829b91321
8 changed files with 439 additions and 644 deletions

View File

@@ -1,8 +1,16 @@
# 可拖拽子窗口项目设计文档
# Vue页面可视化设计器项目文档
## 项目概述
本项目是一个基于 Vite + Vue3 + TypeScript 的可拖拽子窗口系统,模仿 IDE如 IntelliJ IDEA、Visual Studio的界面设计提供多区域可拖拽的窗口管理功能
本项目是一个基于 Vite + Vue3 + TypeScript 的**可视化页面设计器**通过拖拽操作直接编辑真实的Vue页面文件实现低代码页面快速构建
## 核心特性
1. **直接解析Vue文件** - 动态渲染真实的.vue页面
2. **拖拽式设计** - 将设计组件拖拽到页面的el-row/el-col上
3. **层级选择** - 通过键盘方向键切换嵌套元素的选中层级
4. **实时预览** - 拖拽时显示放置方向(上/下/左/右)
5. **结构化ID** - 自动生成路径ID如r1c2r1c1
## 技术架构
@@ -17,127 +25,196 @@
### 项目结构
```
src/
├── assets/ # 静态资源
├── components/ # 核心UI组件
│ ├── Header.vue # 顶部菜单栏
│ ├── Footer.vue # 底部状态栏
│ ├── MainLayout.vue # 主布局容器
│ ├── Panel.vue # 面板容器
│ └── Resizer.vue # 面板分隔器
├── materials/ # 物料组件系统
│ ├── index.ts # 物料组件注册中心
│ ├── TextEditor/ # 文本编辑器
├── TreeViewer/ # 树形展示器
│ ├── DataTable/ # 数据表格
│ ├── TestWidget*/ # 测试组件
│ ├── DesignComponentList/ # 设计组件列表
│ └── DesignCenter/ # 设计中心
├── designComponents/ # 设计组件库
│ ├── TextInput/ # 文本输入框
│ ├── RadioSelect/ # 单选器
│ └── GridTable/ # 表格组件
├── stores/ # 状态管理
│ ├── panelStore.ts # 面板布局状态
── designStore.ts # 设计中心状态
├── types/ # TypeScript 类型定义
└── App.vue # 应用入口
├── fauto/ # 核心功能模块
├── components/ # UI组件
│ ├── Header.vue # 顶部菜单栏
│ ├── Footer.vue # 底部状态栏(显示拖拽状态)
│ ├── MainLayout.vue # 主布局容器
│ ├── Panel.vue # 面板容器
│ └── Resizer.vue # 面板分隔器
├── materials/ # 物料组件系统
│ ├── PageManagement/ # 页面管理树形选择Vue文件
│ ├── DesignComponentList/ # 设计组件列表
│ └── DesignCenter/ # 设计中心(动态渲染页面)
│ ├── designComponents/ # 设计组件库
│ ├── TextInput/ # 文本输入框
│ ├── RadioSelect/ # 单选器
│ └── GridTable/ # 表格组件
│ ├── plugins/ # 插件系统(交互事件、拖拽管理)
│ ├── interactionStore.ts # 全局交互钩子
│ ├── dragStore.ts # 拖拽状态管理
│ └── pathUtils.ts # 结构化路径工具
├── stores/ # 状态管理
│ ├── panelStore.ts # 面板布局状态
│ ├── designStore.ts # 设计组件元数据
└── vueFileStore.ts # Vue文件选择状态
│ └── Designer.vue # 设计器主入口
├── views/ # 示例页面(测试用)
└── App.vue # 应用入口
```
## 核心功能模块
### 1. 面板系统 (Panel System)
### 1. 页面管理系统
#### 布局结构
- **Header**: 固定顶部,包含菜单和新增窗口按钮
- **MainLayout**: 三区域布局(左/中/右)
- **Panel**: 可拖拽的面板容器
- **Footer**: 固定底部,显示时间和状态信息
#### 功能说明
- 动态扫描`src/views`目录下的所有Vue文件
- 以树形结构展示文件夹和页面
- 点击选中后在设计中心动态渲染
#### 拖拽实现
使用 `vuedraggable` 库实现跨面板的 Tab 拖拽:
```vue
<draggable
:list="panel.tabs"
group="tabs"
item-key="id"
:animation="150"
>
#### 技术实现
```typescript
// 使用import.meta.glob动态扫描
const viewModules = import.meta.glob('../../../views/**/*.vue')
// 异步加载选中的组件
const loader = viewModules[selectedFilePath]
const component = defineAsyncComponent(loader)
```
### 2. 物料组件系统 (Material System)
### 2. 设计中心系统
#### 规范标准
遵循统一的物料组件规范:
1. 每个组件独立文件夹
2. 包含 `index.vue`(组件实现)和 `index.json`(元数据)
3. `index.json` 定义:名称、描述、属性及默认值
#### InteractiveWrapper交互包装器
**作用**为动态渲染的Vue页面注入交互事件
#### 组件状态管理
- 使用 `materialState` 属性传递组件状态
- 通过 `update:state` 事件实现状态更新
- 物料组件状态独立存储,组件关闭后状态仍保留
**核心功能**
1. 自动扫描页面中的el-row和el-col
2. 为每个元素注入结构化路径ID`r1c2`
3. 绑定交互事件(悬停、点击、拖拽)
4. 使用MutationObserver监听DOM变化
#### 状态持久化
通过自定义 Vite 插件实现 API 中间件:
- `/api/config`: 布局配置读写
- `/api/material-states`: 物料组件状态读写
- `/api/design-components`: 设计组件元数据读取
- `/api/design-state`: 设计中心状态读写
#### DropZone拖放区域指示器
**作用**:拖拽时显示可放置区域
### 3. 设计组件系统 (Design System)
**显示规则**
- el-row显示 **上方****下方** 两个区域
- el-col显示 **左侧****右侧** 两个区域
#### 组件构成
1. **设计组件库** (`designComponents/`)
- TextInput: 文本输入框属性label, width, maxLength
- RadioSelect: 单选器属性options
- GridTable: 表格属性rows, columns, headers
#### DragPreview拖拽预览
跟随鼠标显示正在拖拽的内容,提供视觉反馈。
2. **物料组件**
- DesignComponentList: 展示可用设计组件
- DesignCenter: 展示已添加的设计组件实例
- TreeViewer: 展示设计中心组件列表(支持拖拽排序)
- DataTable: 展示选中组件的属性(支持编辑)
### 3. 插件系统 (fauto/plugins)
#### 跨组件联动机制
1. 点击 DesignComponentList 中的组件添加到 DesignCenter
2. 点击 DesignCenter 中的组件,在 DataTable 中展示其属性
3. 在 TreeViewer 中拖拽组件调整 DesignCenter 的顺序
4. 在 DataTable 中双击属性值进行编辑
#### interactionStore交互状态管理
管理所有交互事件的全局状态:
- `hoverTarget`: 当前悬停的元素
- `selectedTarget`: 当前选中的元素
- 提供全局事件钩子hover, click, longpress, drag, release
#### dragStore拖拽状态管理
管理拖拽操作的复杂状态:
**核心状态**
- `dragSource`: 拖拽源(设计组件/画布元素)
- `hierarchyNodes`: 当前悬停位置的所有层级节点
- `selectedHierarchyIndex`: 当前选中的层级索引
- `hoverDirection`: 当前悬停的拖放方向
- `lastDropRecord`: 最后一次拖放记录
**层级选择机制**
- 鼠标悬停在嵌套元素上时,自动识别所有父级节点
- 默认选中最深层级
- **↑键**:切换到父级
- **↓键**:切换到子级
- **Esc键**:取消拖拽
#### pathUtils路径工具
生成和解析结构化路径ID
**路径格式**`r{n}c{m}r{x}c{y}...`
- `r`: el-row
- `c`: el-col
- 数字在同级元素中的索引从1开始
**示例**`r1c2r1c3` 表示:
- 第1个el-row
- 的第2个el-col
- 内的第1个el-row
- 内的第3个el-col
## 状态管理设计
### PanelStore (面板状态)
### PanelStore面板状态
管理整个应用的布局和物料组件状态:
- `layout`: 三区域面板配置
- `materialStates`: 物料组件状态独立存储
- 提供 Tab 操作 API添加、关闭、移动、激活
### DesignStore (设计中心状态)
管理设计组件系统的状态
- `components`: 已添加的设计组件实例列表
- `selectedId`: 当前选中的组件实例ID
- `componentMetas`: 设计组件元数据缓存
### DesignStore(设计组件元数据)
管理设计组件的元数据
- `componentMetas`: 设计组件元数据列表
- `loadComponentMetas()`: 动态扫描设计组件目录
- `getComponentMeta()`: 获取指定组件元数据
### VueFileStoreVue文件状态
管理页面管理的选中状态:
- `selectedFilePath`: 当前选中的文件路径
- `selectedFileName`: 当前选中的文件名
- `selectFile()`: 选中指定文件
### InteractionStore / DragStore
见**插件系统**部分
## 实现细节
### 1. 拖拽功能优化
- 使用 `:list` 属性而非 `v-model` 解决拖拽位置问题
- 实现跨面板 Tab 拖拽
- 面板宽度可调整(通过 Resizer 组件)
### 1. Vue页面规范
**强制规则**template的第一层级**有且仅有一个el-row**
### 2. 状态持久化策略
- 布局配置和物料状态分别存储
- 使用防抖机制避免频繁保存TextEditor 500ms
- 组件移除后状态仍保留
**目的**:保证布局可解析性,方便自动生成结构化路径
### 3. 组件通信机制
- 父子组件Props / Events
- 兄弟组件:通过 Pinia Store
- 物料组件:`materialState` / `update:state`
示例:
```vue
<template>
<el-row :gutter="20">
<el-col :span="12">
<div class="design-component">左侧内容</div>
</el-col>
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="24">
<div class="design-component">标题</div>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
```
### 2. 拖拽交互优化
#### 禁用文本选择
拖拽时给body添加`is-dragging`类,设置`user-select: none`
#### 拖拽预览效果
DragPreview组件跟随鼠标显示
- 组件图标 + 名称
- 动画效果(缩放 + 淡入)
- Teleport到body避免z-index问题
### 3. 层级选择实现
```typescript
// 递归遍历DOM生成层级节点
const updateHierarchy = (element: HTMLElement) => {
const nodes: HierarchyNode[] = []
let current: HTMLElement | null = element
while (current) {
if (current.classList.contains('el-row') ||
current.classList.contains('el-col')) {
nodes.push({ path, type, element, depth })
}
current = current.parentElement
}
// 按深度排序,最深的在前
nodes.sort((a, b) => b.depth - a.depth)
}
```
### 4. 性能优化
- 使用 `defineAsyncComponent` 异步加载物料组件
- 使用 `markRaw` 避免不必要的响应式转换
- 使用 `defineAsyncComponent` 异步加载页面
- 使用 `MutationObserver` 监听DOM变化
- 防止重复绑定(`data-fauto-bindend`属性)
- 使用 `computed` 缓存派生数据
## API 设计
@@ -159,6 +236,11 @@ POST /api/design-state # 保存设计中心状态
## 开发规范
### Vue页面结构规范
1. template第一层级有且仅有一个el-row
2. el-row内只能包含el-col或div设计组件
3. div使用class="design-component"标识
### 代码规范
1. 使用 TypeScript 严格模式
2. 组件 Props 必须明确定义类型
@@ -167,33 +249,32 @@ POST /api/design-state # 保存设计中心状态
### 组件开发规范
1. 遵循物料组件标准化规范
2. 状态通过 `materialState` 接收,通过 `update:state` 更新
3. 实现防抖保存机制避免频繁 IO
4. 提供清晰的组件文档index.json
2. 每个组件包含`index.vue``index.json`
3. 插件相关代码放在`fauto/plugins`目录
### 状态管理规范
1. 使用 Pinia 进行全局状态管理
2. 状态变更必须通过 Store 的方法
3. 复杂状态逻辑封装在 Store 内部
4. 状态持久化与 UI 逻辑分离
## 扩展性设计
### 新增物料组件
1.`materials/` 目录下创建组件文件夹
2. 实现 `index.vue``index.json`
3.`materials/index.ts` 中注册组件
### 新增设计组件
1.`designComponents/` 目录下创建组件文件夹
2. 实现 `index.vue``index.json`
3. 在 DesignComponentList 中会自动显示
3. 自动在 DesignComponentList 中显示
### 功能扩展
1. 面板系统支持更多布局模式
2. 物料组件支持更多交互类型
3. 设计系统支持更复杂的属性编辑器
1. **拖放后修改源文件** - 通过API将拖放操作写入.vue文件
2. **属性编辑器** - 展示和编辑设计组件属性
3. **热更新同步** - 修改后自动刷新页面
## 总结
本项目实现了完整的可拖拽子窗口系统,具备良好的架构设计和扩展性。通过物料组件系统和设计组件系统的分离,既满足了基础的窗口管理需求,又提供了高级的设计能力。状态持久化机制确保了用户体验的连续性,而规范化的开发流程保证了项目的可维护性
本项目实现了一个完整的**Vue页面可视化设计器**通过直接解析和编辑真实的Vue文件实现了低代码的页面构建方式
**核心亮点**
1. **非侵入式设计** - 通过注入式交互无需修改Vue页面代码
2. **智能层级选择** - 自动识别嵌套结构,键盘切换层级
3. **实时视觉反馈** - 拖拽预览 + 拖放区域指示
4. **结构化路径** - 自动生成可读的元素ID