Files
fauto-design/项目设计文档.md
2026-01-20 22:07:05 +08:00

12 KiB
Raw Permalink Blame History

Vue页面可视化设计器 - 项目设计文档

1. 项目概述

本项目是一个基于 Vue3 + TypeScript + Element Plus 的可视化页面设计器通过拖拽操作直接编辑真实的Vue源文件实现低代码页面快速构建。

1.1 核心特性

特性 描述
直接解析Vue文件 动态渲染真实的.vue页面
源码级修改 拖拽操作直接修改Vue源文件
智能层级选择 键盘方向键切换嵌套元素层级
元数据编辑 可视化编辑组件属性
多视图联动 设计中心、结构树、元数据面板同步选中
热更新 修改后自动刷新预览

1.2 技术架构

┌─────────────────────────────────────────────────────────────────┐
│                       前端应用 (Vue3 + Vite)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐        │
│  │ 页面管理 │  │设计组件列│  │ 设计中心 │  │ 元数据   │        │
│  │          │  │表        │  │          │  │ 编辑器   │        │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘        │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Pinia 状态管理 + 插件系统                     │   │
│  │  dragStore │ interactionStore │ designStore │ vueFileStore│   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │ HTTP API
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│               后端服务 (Node.js + Express)                       │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │     templateService - Vue模板AST解析与修改                 │   │
│  │     @vue/compiler-sfc + @vue/compiler-dom                 │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │ 文件操作
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Vue源文件 (src/views/*.vue)                   │
└─────────────────────────────────────────────────────────────────┘

2. 核心模块设计

2.1 前端模块

2.1.1 设计中心 (DesignCenter)

职责动态渲染选中的Vue页面注入交互事件

核心组件

  • index.vue - 主容器动态加载Vue页面组件
  • InteractiveWrapper.vue - 交互包装器,注入事件监听
  • DropZone.vue - 拖放区域指示器
  • DragPreview.vue - 拖拽跟随预览

交互事件注入流程

// 1. 动态渲染页面组件
<component :is="selectedPageComponent" />

// 2. 挂载后扫描DOM注入事件
const injectInteractionEvents = () => {
  document.querySelectorAll('.el-row, .el-col').forEach(el => {
    const path = generateElementPath(el)  // 生成结构化路径
    bindElementEvents(el, type, path)     // 绑定交互事件
  })
}

// 3. MutationObserver监听DOM变化动态注入
observer.observe(container, { childList: true, subtree: true })

2.1.2 结构树 (TreeViewer)

职责展示页面的el-row/el-col结构支持选中和删除

功能

  • 树形展示页面结构
  • 点击节点选中对应元素
  • 拖拽节点调整顺序
  • 右键菜单/删除图标/Del键删除

2.1.3 元数据编辑器 (DataTable)

职责:展示和编辑选中组件的属性

支持的属性类型

  • number - 数字输入如span宽度
  • text - 文本输入如placeholder
  • select - 下拉选择如size尺寸
  • boolean - 开关切换如stripe斑马纹
  • color - 颜色选择器

2.1.4 插件系统 (plugins/)

dragStore - 拖拽状态管理

interface DragStore {
  // 状态
  isDragging: boolean
  dragPhase: 'source' | 'target'  // 两阶段拖拽
  dragSource: DragSource | null
  hierarchyNodes: HierarchyNode[] // 层级节点列表
  selectedHierarchyIndex: number  // 当前选中层级
  hoverDirection: Direction | null
  
  // 方法
  startDragFromCanvas(path, type, element)  // 开始画布内拖拽
  startDragFromComponentList(id, name, template)  // 开始组件列表拖拽
  enterTargetPhase(element)  // 进入目标选择阶段
  selectParentLevel()  // 选择父级(↑键)
  selectChildLevel()   // 选择子级(↓键)
  confirmDrop(pagePath)  // 确认拖放
}

interactionStore - 交互事件钩子

interface InteractionStore {
  hoverTarget: InteractionTarget | null
  selectedTarget: InteractionTarget | null
  
  onHover(target)
  onClick(target)
  onLeave()
}

2.2 后端模块

2.2.1 templateService

职责解析Vue文件执行结构修改

核心函数

函数 功能
moveElement(vueContent, options) 移动元素到新位置
insertElement(vueContent, options) 插入新元素
deleteElement(vueContent, elementPath) 删除元素
parseElementTree(vueContent) 解析页面结构树
parseComponentProps(vueContent, path) 获取组件属性
updateComponentProps(vueContent, path, updates) 更新组件属性

技术实现

// 使用 @vue/compiler-sfc 解析Vue文件
import { parse as parseSFC } from '@vue/compiler-sfc'
// 使用 @vue/compiler-dom 解析template获取AST
import { parse as parseTemplate } from '@vue/compiler-dom'

// 通过AST定位元素使用字符串操作修改保持原始格式

3. 数据结构设计

3.1 结构化路径

格式r{n}c{m}r{x}c{y}...

前缀 含义
r el-row
c el-col
数字 同级元素中的索引从1开始

示例r1c2r1 = 第1个row → 第2个col → 第1个row

3.2 设计组件配置

{
  "id": "TextInput",
  "name": "输入框",
  "icon": "✏️",
  "description": "用于输入文本内容的表单组件",
  "defaultSpan": 12,
  "metadata": {
    "span": {
      "label": "宽度",
      "type": "number",
      "min": 1,
      "max": 24,
      "target": "el-col",
      "attr": ":span"
    },
    "placeholder": {
      "label": "占位符",
      "type": "text",
      "target": "el-input",
      "attr": "placeholder"
    }
  }
}

3.3 设计组件模板

<el-col :span="12">
  <div class="design-component design-text-input" data-component="输入框">
    <el-form-item label="文本输入">
      <el-input v-model="inputValue" placeholder="请输入内容"></el-input>
    </el-form-item>
  </div>
</el-col>

关键点

  • 外层必须是 el-col
  • 内层 div 必须有 data-component 属性标识组件类型
  • 使用 class="design-component" 标识设计组件

4. API设计

4.1 元素操作API

移动元素

POST /api/move-element
Body: {
  "pagePath": "D:/workspace/.../TestPage1.vue",
  "source": {
    "type": "canvas-element",
    "path": "r1c1",
    "elementType": "ec"
  },
  "targetPath": "r1c2",
  "targetType": "ec",
  "direction": "right"  // top|bottom|left|right|inside
}

插入元素

POST /api/insert-element
Body: {
  "pagePath": "...",
  "templateContent": "<el-col :span=\"12\">...</el-col>",
  "targetPath": "r1c1",
  "direction": "right"
}

删除元素

POST /api/delete-element
Body: {
  "pagePath": "...",
  "elementPath": "r1c2"
}

4.2 属性操作API

获取组件属性

GET /api/component-props?pagePath=...&elementPath=r1c1
Response: {
  "success": true,
  "componentId": "输入框",
  "props": {
    "span": 12,
    "el-input:placeholder": "请输入"
  }
}

更新组件属性

POST /api/update-props
Body: {
  "pagePath": "...",
  "elementPath": "r1c1",
  "updates": {
    "span": 8,
    "el-input:placeholder": "新占位符"
  }
}

4.3 结构查询API

获取页面结构树

GET /api/element-tree?pagePath=...
Response: {
  "success": true,
  "tree": [
    {
      "type": "row",
      "path": "r1",
      "label": "el-row",
      "children": [
        {
          "type": "col",
          "path": "r1c1",
          "componentName": "输入框",
          "children": []
        }
      ]
    }
  ]
}

5. 交互设计

5.1 拖拽流程

1. 用户开始拖拽(组件列表/画布元素)
   ↓
2. 进入源选择阶段,收集层级节点
   ↓
3. 移动到目标位置,进入目标选择阶段
   ↓
4. 显示DropZone上/下/左/右/放入)
   ↓
5. 用户点击方向确认拖放
   ↓
6. 调用后端API修改源文件
   ↓
7. 触发vue-template-updated事件
   ↓
8. 前端刷新页面和结构树

5.2 层级选择

当鼠标悬停在嵌套元素上时(如r1c1r1c1

  • 默认选中最深层级r1c1r1c1
  • ↑键切换到父级r1c1r1 → r1c1 → r1
  • ↓键:切换到子级
  • Esc:取消拖拽

5.3 多视图联动

  • 点击设计中心元素 → 结构树高亮 + 元数据面板更新
  • 点击结构树节点 → 设计中心高亮 + 元数据面板更新
  • 元数据面板修改 → 源文件更新 → 设计中心刷新

6. 扩展指南

6.1 添加设计组件

  1. src/fauto/designComponents/ 创建目录
  2. 添加 index.json(配置+元数据schema
  3. 添加 template.html(组件模板)
  4. 自动在组件列表显示

6.2 添加物料组件

  1. src/fauto/materials/ 创建目录
  2. 添加 index.vue(组件实现)
  3. 添加 index.json(配置信息)
  4. materials/index.ts 注册

6.3 扩展元数据类型

designStore.tsMetadataField 接口添加新类型,并在 DataTable/index.vue 添加对应的编辑控件。


7. 技术规范

7.1 Vue页面规范

<template>
  <!-- 第一层级必须且只能有一个el-row -->
  <el-row :gutter="20">
    <el-col :span="24">
      <!-- 设计组件必须有data-component属性 -->
      <div class="design-component" data-component="组件名">
        <!-- 组件内容 -->
      </div>
    </el-col>
  </el-row>
</template>

7.2 代码规范

  • TypeScript 严格模式
  • Composition API 组织代码
  • Props 必须定义类型
  • 样式使用 scoped
  • 插件代码放 fauto/plugins/

8. 版本信息

  • 前端框架: Vue 3.5.24
  • 构建工具: Vite 7.3.0
  • 状态管理: Pinia 3.0.4
  • UI框架: Element Plus
  • 后端运行时: Node.js
  • 模板解析: @vue/compiler-sfc, @vue/compiler-dom

文档更新时间2026-01-20