---
title: 使用 Vue 定义节点
order: 14
---
在 G6 中,自定义节点通常需要操作 DOM 或 Canvas 元素,但借助 [`g6-extension-vue`](https://github.com/Child-qjj/g6-extension-vue) 社区生态库,可以直接使用 Vue 组件作为节点内容,提升开发效率与可维护性。
### G6 节点
✅ **推荐场景:**
- 节点只是简单的几何图形
- 需要高效渲染超过 2,000 个节点的场景
- 需要直接操作图形实例进行精细控制
> 有关如何使用 Canvas 图形自定义节点的详细信息,请参阅 [自定义节点](/manual/element/node/custom-node) 文档
### Vue Node
✅ **推荐场景:**
- 需要集成 Element Plus / Ant Design Vue 等 UI 库的业务系统
- 节点包含表单输入、状态切换等交互逻辑
- 已有 Vue 设计系统需要复用的场景
## 快速入门
### 环境准备
在开始之前,请确保您已经:
- **安装 Vue 项目**:确保已安装并创建 Vue 项目。
- **Vue 版本要求**:确保使用的 Vue 版本 >=2.6.0。(推荐使用 Vue 3)
### 安装依赖
要使用 [`g6-extension-vue`](https://github.com/Child-qjj/g6-extension-vue),请运行以下命令:
:::code-group
```bash [npm]
npm install g6-extension-vue
```
```bash [yarn]
yarn add g6-extension-vue
```
```bash [pnpm]
pnpm add g6-extension-vue
```
:::
### 组件集成
#### 1. 注册 Vue 节点类型
通过扩展机制注册 Vue 节点类型:
```jsx
import { ExtensionCategory, register } from '@antv/g6';
import { VueNode } from 'g6-extension-vue';
register(ExtensionCategory.NODE, 'vue-node', VueNode);
```
`register` 方法需要三个参数:
- 扩展类别:`ExtensionCategory.NODE` 表示这是一个节点类型
- 类型名称:`vue-node` 是我们给这个自定义节点起的名字,后续会在配置中使用
- 类定义:VueNode 是 `g6-extension-vue` 导出的实现类
#### 2. 定义业务组件
定义一个简单的 Vue 组件作为节点的内容:
```jsx
import { defineComponent, h } from 'vue';
const MyVueNode = defineComponent({
setup(props, { attrs, slots, expose }) {
return () => {
return h('div', 'vue node');
};
},
});
```
#### 3. 使用组件
在图配置中使用自定义的 Vue 节点。通过在图配置中指定节点类型和样式,来使用自定义的 Vue 组件。
- `type`:指定节点类型为 `vue-node` (使用与注册时起的名字)
- `style.component`:定义节点的 Vue 组件内容
```jsx
const graph = new Graph({
node: {
type: 'vue-node',
style: {
component: () => ,
},
},
});
graph.render();
```
## 高级功能
### 状态管理
在复杂图可视化场景中,节点需要动态响应交互状态。我们提供两种互补的状态管理方案:
#### 响应内置交互状态
G6 提供内置的交互状态管理状态,如 `hover-activate` 和 `click-select`。可以通过节点数据中的 `data.states` 字段获取当前节点状态,并根据状态调整节点样式。
**示例**:在节点被 hover 时改变背景颜色。
```jsx
import { ExtensionCategory, register, Graph } from '@antv/g6';
import { VueNode } from 'g6-extension-vue';
import { computed, defineComponent } from 'vue';
register(ExtensionCategory.NODE, 'vue-node', VueNode);
const StatefulNode = defineComponent({
setup(props, { attrs, slots, expose }) {
const isActive = computed(() => props.data.states?.includes('active'));
const label = computed(() => props.data.data?.label);
return (
{label.value}
);
},
});
const graph = new Graph({
data: {
nodes: [
{ id: 'node1', style: { x: 100, y: 200 }, data: { label: 'node1' } },
{ id: 'node2', style: { x: 300, y: 200 }, data: { label: 'node2' } },
],
},
node: {
type: 'vue-node',
style: {
component: (data) => , // data是非响应式数据,需要通过改变引用来触发Vue的props副作用
},
},
behaviors: ['hover-activate'],
});
graph.render();
```
#### 自定义业务状态
当需要管理业务相关状态(如审批状态、风险等级)时,可通过扩展节点数据实现:
**示例**:通过 data 添加 `selected` 变量,实现节点选中和取消选中的样式变化。
```jsx
import { ExtensionCategory, register, Graph } from '@antv/g6';
import { VueNode } from 'g6-extension-vue';
import { defineComponent, computed } from 'vue';
register(ExtensionCategory.NODE, 'vue-node', VueNode);
const MyVueNode = defineComponent({
setup(props, { attrs, slots, expose }) {
const isSelected = computed(() => props.data.data.selected);
const handleClick = () => {
graph.updateNodeData([{ id: props.data.id, data: { selected: !isSelected.value } }]);
graph.draw();
};
return (
Node
);
},
});
const graph = new Graph({
data: {
nodes: [
{
id: 'node1',
style: { x: 100, y: 100 },
data: { selected: true },
},
],
},
node: {
type: 'vue-node',
style: {
component: (data) => , // data是非响应式数据,需要通过改变引用来触发Vue的props副作用
},
},
});
graph.render();
```
### 事件交互
实现节点与图实例的双向通信,使节点和图实例可以相互更新。
**示例**:通过自定义节点操作图数据,并重新渲染图形。
```jsx
import { ExtensionCategory, register, Graph } from '@antv/g6';
import { VueNode } from 'g6-extension-vue';
import { defineComponent, computed } from 'vue';
register(ExtensionCategory.NODE, 'vue-node', VueNode);
const IDCardNode = defineComponent({
setup(props, { attrs, slots, expose }) {
const isSelected = computed(() => props.data.data.selected);
const handleSelect = () => {
graph.updateNodeData([{ id: props.data.id, data: { selected: true } }]);
graph.draw();
};
return ;
},
});
const graph = new Graph({
node: {
type: 'vue-node',
style: {
component: ({ id, data }) => ,
},
},
});
```