UNPKG

vue2-mind-map

Version:

`vue2-mind-map` 是一个功能丰富的思维导图可视化组件。该组件提供了完整的思维导图展示和交互功能,支持多种数据格式输入、灵活的布局配置、丰富的样式定制和流畅的用户交互体验。目前基于 Vue 2 构建。

541 lines (436 loc) 17.4 kB
# vue2-mind-map 组件使用文档 `vue2-mind-map` 是一个功能丰富的思维导图可视化组件。该组件提供了完整的思维导图展示和交互功能,支持多种数据格式输入、灵活的布局配置、丰富的样式定制和流畅的用户交互体验。目前基于 Vue 2 构建。 ### TODO - 支持 Vue 3 - 触摸屏支持 - 操作历史及回滚 - 小地图 ## 数据结构说明 ### TreeNode(树形数据结构) 用于描述具有层级关系的思维导图节点,通过 `children` 数组直接表示父子关系: - **id** `string` (可选) - 节点唯一标识符 - **position** `object` (可选) - 节点位置坐标,格式:`{ x: number, y: number }` - **size** `object` (可选) - 节点尺寸,格式:`{ x: number, y: number }` - **children** `array` (可选) - 子节点数组,每个元素都是 TreeNode 结构 - **collapsed** `boolean` (可选) - 节点是否折叠,默认为 `false` - **content** `string|HTMLElement|array|function` (可选) - 节点显示内容 - **[自定义属性]** `any` - 可以添加任意自定义属性 **示例**```javascript const treeData = { id: 'root', content: '根节点', children: [ { id: 'child1', content: '子节点1', collapsed: false, children: [ { id: 'grandchild1', content: '孙节点1' } ] }, { id: 'child2', content: '子节点2' } ] } ``` ### FlatNode(扁平数据结构) 用于描述扁平化的思维导图节点,通过 `parentId` 间接表示父子关系: - **id** `string` (可选) - 节点唯一标识符 - **parentId** `string` (可选) - 父节点ID,根节点可以不设置 - **position** `object` (可选) - 节点位置坐标,格式:`{ x: number, y: number }` - **size** `object` (可选) - 节点尺寸,格式:`{ x: number, y: number }` - **collapsed** `boolean` (可选) - 节点是否折叠,默认为 `false` - **content** `string|HTMLElement|array|function` (可选) - 节点显示内容 - **[自定义属性]** `any` - 可以添加任意自定义属性 **示例**```javascript const flatData = [ { id: 'root', content: '根节点' }, { id: 'child1', parentId: 'root', content: '子节点1' }, { id: 'child2', parentId: 'root', content: '子节点2' }, { id: 'grandchild1', parentId: 'child1', content: '孙节点1' } ] ``` ## 配置选项说明 ### 对齐配置 (MindMapAlign) 控制思维导图节点的对齐方式: - **mode** `string` - 对齐模式,可选值: - `"cross-axis-start-edge"` - 交叉轴起始边对齐(默认) - `"cross-axis-center"` - 交叉轴居中对齐 - `"node-center"` - 以指定节点为中心对齐 - **targetNodeId** `string` (可选) - 目标节点ID,仅在 `mode``"node-center"` 时使用 ### 拖拽配置 (MindMapDragOptions) 控制思维导图的拖拽行为: - **enableNodeDrag** `boolean` (可选) - 是否启用节点拖拽,默认 `false` - **enableCanvasDrag** `boolean` (可选) - 是否启用画布拖拽,默认 `true` - **dragNodeButton** `number|array` (可选) - 拖拽节点的鼠标按钮,默认左键(0) - **dragCanvasButton** `number|array` (可选) - 拖拽画布的鼠标按钮,默认右键(2)和中键(1) - **useThrottle** `boolean` (可选) - 是否使用节流减少事件触发频率,默认 `true` **鼠标按钮值**:左键=0,中键=1,右键=2 ### 缩放配置 (MindMapZoomOptions) 控制思维导图的缩放行为: - **enableWheelZoom** `boolean` (可选) - 是否启用滚轮缩放,默认 `true` - **zoomStep** `number` (可选) - 每次缩放步长,默认 `0.1` (10%) - **invertWheelDirection** `boolean` (可选) - 是否反转滚轮方向,默认 `false` - **minZoom** `number` (可选) - 最小缩放比例,默认 `0.1` (10%) - **maxZoom** `number` (可选) - 最大缩放比例,默认 `5.0` (500%) ## Props ### 基础配置 **`data`** (必填) - 类型: TreeNode 对象 或 FlatNode 数组 - 描述: 思维导图的数据源 **`direction`** - 类型: `"horizontal" | "vertical"` - 默认值: `"horizontal"` - 描述: 思维导图的布局方向 ### 样式配置 **`line-style`** - 类型: `"straight" | "curved" | "zigzag"` - 默认值: `"curved"` - 描述: 连接线的样式 **`line-color`** - 类型: `String` - 默认值: `"#000000"` - 描述: 连接线的颜色 **`line-width`** - 类型: `Number` - 默认值: `1` - 描述: 连接线的宽度,单位像素 **`node-border-width`** - 类型: `Number` - 默认值: `1` - 描述: 节点边框的宽度,单位像素 **`node-bg-color`** - 类型: `String` - 默认值: `"#FFFFFF"` - 描述: 节点背景颜色 **`node-border-color`** - 类型: `String` - 默认值: `"#000000"` - 描述: 节点边框颜色 ### 布局配置 **`align`** - 类型: MindMapAlign 配置对象 - 默认值: `{ mode: "cross-axis-start-edge" }` - 描述: 思维导图对齐方式配置 **`sibling-separation`** - 类型: `Number` - 默认值: `25` - 描述: 同级节点之间的间距,单位像素 **`level-separation`** - 类型: `Number` - 默认值: `50` - 描述: 层级之间的间距,单位像素 **`initial-offset`** - 类型: `Object` - 默认值: `undefined` - 描述: 思维导图的初始偏移量,格式:`{ x: number, y: number }` ### 交互配置 **`drag-options`** - 类型: MindMapDragOptions 配置对象 - 默认值: `{ enableNodeDrag: false, enableCanvasDrag: true, dragCanvasButton: [2, 1], useThrottle: true }` - 描述: 拖拽相关配置 **`zoom-options`** - 类型: MindMapZoomOptions 配置对象 - 默认值: `{ enableWheelZoom: true, zoomStep: 0.1, invertWheelDirection: false, minZoom: 0.1, maxZoom: 5.0 }` - 描述: 缩放相关配置 ## 方法 (Methods) 你可以通过获取 `MindMap.vue` 组件的引用 (ref) 来调用其公开方法。 **示例**: ```vue <template> <mind-map ref="mindMapRef" :data="mindMapData" /> </template> <script> export default { mounted() { // 调用 rebuild 方法 this.$refs.mindMapRef.rebuild(); } }; </script> ``` ### 布局和渲染控制 **`rebuild()`** - 描述: 重置思维导图布局并重新渲染 - 返回: `void` **`clear()`** - 描述: 清空思维导图实例的所有内容和状态 - 返回: `void` **`setHorizontal(isHorizontal)`** - 参数: `isHorizontal: boolean` - 布局方向,`true` 为水平,`false` 为垂直 - 描述: 设置思维导图布局方向 - 返回: `void` ### 缩放控制 **`zoomIn(cx?, cy?)`** - 参数: - `cx?: number` - 缩放中心点的 X 坐标(可选) - `cy?: number` - 缩放中心点的 Y 坐标(可选) - 描述: 放大思维导图 - 返回: `void` **`zoomOut(cx?, cy?)`** - 参数: - `cx?: number` - 缩放中心点的 X 坐标(可选) - `cy?: number` - 缩放中心点的 Y 坐标(可选) - 描述: 缩小思维导图 - 返回: `void` **`resetZoom(cx?, cy?)`** - 参数: - `cx?: number` - 缩放中心点的 X 坐标(可选) - `cy?: number` - 缩放中心点的 Y 坐标(可选) - 描述: 重置思维导图缩放比例到 1.0 - 返回: `void` ### 节点操作 **`setNodeSize(nodeId, size)`** - 参数: - `nodeId: string` - 要设置尺寸的节点 ID - `size: { width?: number; height?: number }` - 新的节点尺寸 - 描述: 设置指定节点的尺寸 - 返回: `boolean | undefined` - 如果节点找到并成功设置尺寸,则返回 `true`;否则返回 `false` **`focusOnNode(nodeId)`** - 参数: `nodeId: string` - 节点ID - 描述: 将指定节点聚焦到视口中心 - 返回: `boolean | undefined` - 如果节点找到并成功聚焦,则返回 `true`;否则返回 `false` **`toggleNodeCollapse(nodeId)`** - 参数: `nodeId: string` - 节点ID - 描述: 切换节点的折叠状态 - 返回: `boolean | undefined` - 如果节点找到并成功切换状态,则返回 `true`;否则返回 `false` **`setNodeCollapsed(nodeId, collapsed)`** - 参数: - `nodeId: string` - 节点ID - `collapsed: boolean` - 要设置的折叠状态 - 描述: 设置节点的折叠状态 - 返回: `boolean | undefined` - 如果节点找到并成功设置状态,则返回 `true`;否则返回 `false` **`getNodeCollapsed(nodeId)`** - 参数: `nodeId: string` - 节点ID - 描述: 获取节点的折叠状态 - 返回: `boolean | undefined` - 节点的折叠状态,如果节点不存在则返回 `undefined` **`expandAllNodes()`** - 描述: 展开所有节点 - 返回: `number` - 成功展开的节点数量 **`collapseAllNodes()`** - 描述: 折叠所有非根节点 - 返回: `number` - 成功折叠的节点数量 **`updateNodeContents(nodeIds?)`** - 参数: `nodeIds?: string[]` - 要更新内容的节点 ID 数组,不传参时默认更新所有节点 - 描述: 更新指定节点的内容,此方法会根据节点的 `content` 属性或外部传入的 `contentCallback` 来重新解析和设置节点内部的内容 - 返回: `Promise<number>` - 成功更新的节点个数 ## 插槽 (Slots) ### 默认插槽 - **名称**: `default`(默认插槽) - **作用域**: `{ node: TreeNode | FlatNode }` - **描述**: 自定义节点内容的显示。你可以通过这个作用域插槽来为每个节点提供自定义的 HTML 结构。 - **`node`**: 当前正在渲染的节点对象,包含节点的 ID、位置、子节点等信息。也就是你通过 prop data 传入的节点。 **基础示例**: ```vue <template> <mind-map :data="mindMapData"> <template v-slot="{ node }"> <div class="custom-node"> <strong>{{ node.id }}</strong> <p v-if="node.data && node.data.description">{{ node.data.description }}</p> </div> </template> </mind-map> </template> ``` **条件渲染示例**: ```vue <template> <mind-map :data="mindMapData"> <template v-slot="{ node }"> <!-- 方式1: 使用 v-show 控制显示 --> <div v-show="slotIndex === 1" class="node-style-1"> 样式1 - {{ node.id }} </div> <div v-show="slotIndex === 2" class="node-style-2"> 样式2 - {{ node.id }} </div> <!-- 方式2: 使用 v-if 条件渲染 --> <div v-if="node.type === 'important'" class="important-node"> 重要节点: {{ node.id }} </div> <div v-else class="normal-node"> 普通节点: {{ node.id }} </div> </template> </mind-map> </template> ``` **注意事项**: - 插槽内容会被缓存以提高性能,每个节点对应一个 Vue 实例 - 插槽渲染失败时会显示错误信息,并回退到默认渲染 ## 事件 (Events) 你可以通过监听 `MindMap.vue` 组件的事件来响应思维导图的状态变化。 ### 画布拖拽事件 **`canvas-drag-start`** - **触发时机**: 当画布开始被拖拽时触发 - **事件数据**: `MindMapCanvasEvent` 对象 - `originalEvent: MouseEvent` - 原始鼠标事件 - `button: MouseButton | null` - 按下的鼠标按钮 - `mouseX: number` - 拖拽开始时鼠标在容器内的 X 坐标 - `mouseY: number` - 拖拽开始时鼠标在容器内的 Y 坐标 - **描述**: 此事件在画布拖拽开始时触发,可以用于记录拖拽开始状态或执行相关初始化操作 **`canvas-drag`** - **触发时机**: 当画布正在被拖拽时触发 - **事件数据**: `MindMapCanvasEvent` 对象 - `originalEvent: MouseEvent` - 原始鼠标事件 - `button: MouseButton | null` - 按下的鼠标按钮 - `mouseX: number` - 当前鼠标在容器内的 X 坐标 - `mouseY: number` - 当前鼠标在容器内的 Y 坐标 - `deltaX: number` - X 轴拖拽距离 - `deltaY: number` - Y 轴拖拽距离 - **描述**: 此事件在画布拖拽过程中持续触发,可以用于同步画布位置状态或执行跟随操作 **`canvas-drag-end`** - **触发时机**: 当画布拖拽结束时触发 - **事件数据**: `MindMapCanvasEvent` 对象 - `originalEvent: MouseEvent` - 原始鼠标事件 - `button: MouseButton | null` - 按下的鼠标按钮 - `mouseX: number` - 拖拽结束时鼠标在容器内的 X 坐标 - `mouseY: number` - 拖拽结束时鼠标在容器内的 Y 坐标 - **描述**: 此事件在画布拖拽结束时触发,可以用于保存最终状态或执行清理操作 **使用示例**: ```vue <template> <mind-map :data="mindMapData" @canvas-drag-start="handleCanvasDragStart" @canvas-drag="handleCanvasDrag" @canvas-drag-end="handleCanvasDragEnd" /> </template> <script> export default { methods: { handleCanvasDragStart(event) { console.log('画布开始拖拽:', event.mouseX, event.mouseY); }, handleCanvasDrag(event) { console.log('画布拖拽中:', `移动了 ${event.deltaX}, ${event.deltaY}`); }, handleCanvasDragEnd(event) { console.log('画布拖拽结束'); } } }; </script> ``` ### 缩放事件 **`zoom-change`** - **触发时机**: 当思维导图的缩放比例发生变化时触发 - **事件数据**: `MindMapZoomEvent` 对象 - `originalEvent?: WheelEvent` - 原始滚轮事件(如果是滚轮触发的缩放) - `scale: Vector` - 当前的缩放比例向量 {x, y} - `mouseX: number` - 缩放中心在容器内的 X 坐标 - `mouseY: number` - 缩放中心在容器内的 Y 坐标 - **描述**: 此事件在缩放操作(放大、缩小、重置)完成后触发,可以用于同步缩放状态或执行相关联的操作 **使用示例**: ```vue <template> <mind-map :data="mindMapData" @zoom-change="handleZoomChange" /> </template> <script> export default { methods: { handleZoomChange(event) { console.log('缩放比例变化:', `${event.scale.x * 100}%`); console.log('缩放中心:', event.mouseX, event.mouseY); // 同步外部缩放状态 this.currentZoomLevel = event.scale.x; } } }; </script> ``` ### 容器尺寸变化事件 **`container-resize`** - **触发时机**: 当思维导图容器尺寸发生变化时触发 - **事件数据**: `MindMapContainerResizeEvent` 对象 - `width: number` - 新的容器宽度 - `height: number` - 新的容器高度 - **描述**: 此事件在容器尺寸变化时触发,可以用于响应式布局调整或执行相关的重新计算操作 **使用示例**: ```vue <template> <mind-map :data="mindMapData" @container-resize="handleContainerResize" /> </template> <script> export default { methods: { handleContainerResize(event) { console.log('容器尺寸变化:', `${event.width} x ${event.height}`); // 根据新尺寸调整相关组件 this.adjustUIForNewSize(event.width, event.height); }, adjustUIForNewSize(width, height) { // 执行尺寸相关的调整逻辑 } } }; </script> ``` ### 布局更新事件 **`layout-updated`** - **触发时机**: 当思维导图的布局发生变化并更新完成后触发(例如,从水平切换到垂直布局,或重新计算布局后) - **事件数据**: `MindMapLayoutEvent` 对象 - `direction: 'horizontal' | 'vertical'` - 当前的布局方向 - **描述**: 此事件在思维导图完成布局计算和渲染后触发,可以用于同步外部状态或执行需要在布局稳定后进行的操作 **使用示例**: ```vue <template> <mind-map :data="mindMapData" @layout-updated="handleLayoutUpdated" /> </template> <script> export default { methods: { handleLayoutUpdated(event) { console.log('布局已更新,当前方向:', event.direction); // 执行布局更新后的逻辑 } } }; </script> ``` ### 节点折叠状态变化事件 **`node-collapse-changed`** - **触发时机**: 当任何节点的折叠/展开状态发生变化时触发 - **事件数据**: `MindMapNodeCollapseEvent` 对象 - `nodeId: string` - 折叠状态发生变化的节点 ID - `collapsed: boolean` - 当前的折叠状态,`true` 表示已折叠,`false` 表示已展开 - `node: TreeNode | FlatNode` - 被折叠/展开的节点对应的原始数据 - **描述**: 此事件在调用折叠相关方法(如 `toggleNodeCollapse``setNodeCollapsed``expandAllNodes``collapseAllNodes`)时触发,可以用于同步外部状态或记录操作历史 **使用示例**: ```vue <template> <mind-map :data="mindMapData" @node-collapse-changed="handleNodeCollapseChanged" /> </template> <script> export default { methods: { handleNodeCollapseChanged(event) { console.log(`节点 ${event.nodeId} ${event.collapsed ? '折叠' : '展开'}了`); console.log('节点数据:', event.node); // 同步外部状态 this.updateNodeState(event.nodeId, event.collapsed); }, updateNodeState(nodeId, collapsed) { // 更新外部数据或状态管理 } } }; </script> ``` **批量操作事件**: 当调用 `expandAllNodes()``collapseAllNodes()` 方法时,每个状态发生变化的节点都会单独触发一次 `node-collapse-changed` 事件。