Vue3 与 AntV X6 节点传参、自动布局及边颜色控制教程

以下是整理后的 AntV X6 + Vue 3 节点开发全流程指南,包含完整代码示例和关键实现细节:

环境搭建与项目初始化

使用 Vite 快速创建 Vue 3 项目:

bash 复制代码
npm create vite@latest x6-vue-demo
cd x6-vue-demo
npm install

安装核心依赖:

bash 复制代码
npm install @antv/x6 @antv/layout @antv/x6-vue-shape element-plus

配置 Element Plus(在 main.js/ts 中):

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

自定义节点组件开发

创建 NodeView.vue 组件:

vue 复制代码
<template>
  <div class="node" @click="handleClick">
    <div class="node-title">{{ nodeData.name }}</div>
    <div class="node-status">状态: {{ nodeData.status || "未执行" }}</div>
  </div>
</template>

<script setup>
import { ref, onBeforeUnmount } from "vue"
const props = defineProps({ getNode: Function })
const node = props.getNode()
const nodeData = ref(node ? node.getData() : {})

const handleChange = ({ current }) => {
  nodeData.value = { ...current }
}
if (node) node.on("change:data", handleChange)

onBeforeUnmount(() => {
  if (node) node.off("change:data", handleChange)
})

const handleClick = () => {
  alert(`点击了: ${nodeData.value.name}`)
}
</script>

<style scoped>
.node {
  width: 120px;
  height: 50px;
  background: #409eff;
  color: #fff;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  cursor: pointer;
}
.node-title { font-weight: bold; }
.node-status { font-size: 10px; margin-top: 4px; }
</style>

主页面实现

创建 GraphDemo.vue 核心逻辑:

vue 复制代码
<template>
  <div>
    <el-button type="primary" @click="setStatus('成功')">父节点成功</el-button>
    <el-button type="danger" @click="setStatus('失败')">父节点失败</el-button>
    <el-button @click="setStatus('等待')">父节点等待</el-button>
    <div class="graph-container" ref="graphRef"></div>
    <TeleportContainer />
  </div>
</template>

<script setup>
import { ref, onMounted, defineComponent } from "vue"
import { Graph } from "@antv/x6"
import { register, getTeleport } from "@antv/x6-vue-shape"
import { DagreLayout } from "@antv/layout"
import NodeView from "../components/NodeView.vue"

const graphRef = ref(null)
let graph = null
const TeleportContainer = defineComponent(getTeleport())

const initGraph = () => {
  register({
    shape: "vue-node",
    component: NodeView,
    getComponentProps(node) {
      return { getNode: () => node }
    }
  })

  graph = new Graph({
    container: graphRef.value,
    background: { color: "#f9f9f9" },
    grid: true
  })

  const taskList = [
    { id: "1", name: "任务A", status: "等待" },
    { id: "2", name: "任务B", status: "等待" },
    { id: "3", name: "任务C", status: "等待" }
  ]

  const relations = [
    { source: "1", target: "2" },
    { source: "1", target: "3" }
  ]

  const nodes = taskList.map((task) => ({
    id: task.id,
    shape: "vue-node",
    width: 120,
    height: 50,
    data: task
  }))

  const edges = relations.map((rel) => ({
    source: rel.source,
    target: rel.target,
    attrs: {
      line: {
        stroke: "#999",
        strokeWidth: 2,
        targetMarker: { name: "classic", width: 12, height: 8 }
      }
    }
  }))

  const layout = new DagreLayout({
    type: "dagre",
    rankdir: "LR",
    nodesep: 40,
    ranksep: 60
  })

  graph.fromJSON(layout.layout({ nodes, edges }))
  updateEdgesColor()
}

const updateEdgesColor = () => {
  graph.getEdges().forEach((edge) => {
    const sourceNode = graph.getCellById(edge.getSourceCellId())
    const status = sourceNode?.getData()?.status || "等待"
    edge.setAttrs({
      line: { 
        stroke: 
          status === "成功" ? "green" :
          status === "失败" ? "red" : "gray"
      }
    })
  })
}

const setStatus = (status) => {
  const parentNode = graph.getCellById("1")
  parentNode.setData({ ...parentNode.getData(), status })
  updateEdgesColor()
}

onMounted(() => initGraph())
</script>

<style scoped>
.graph-container {
  width: 100%;
  height: 500px;
  border: 1px solid #ddd;
  margin-top: 10px;
}
</style>

关键功能说明

自动布局实现

通过 DagreLayout 自动计算节点位置,参数说明:

  • rankdir: "LR" 控制布局方向(Left to Right)
  • nodesepranksep 控制节点间距

动态边颜色控制
updateEdgesColor 方法根据源节点状态改变连线颜色:

  • 成功状态:绿色边
  • 失败状态:红色边
  • 默认状态:灰色边

节点数据响应式

通过监听 change:data 事件实现节点状态实时更新,注意在组件卸载时移除事件监听

效果说明

运行后可见:

  1. 三个采用自动布局排列的节点
  2. 父节点(任务A)控制两个子节点的边颜色
  3. 点击按钮可切换父节点状态(成功/失败/等待)
  4. 点击节点会显示节点名称提示框
相关推荐
程序员清洒6 分钟前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季66640 分钟前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
天人合一peng1 小时前
Unity中button 和toggle监听事件函数有无参数
前端·unity·游戏引擎
会飞的战斗鸡1 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling2 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_177767372 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767372 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
web打印社区2 小时前
web-print-pdf:突破浏览器限制,实现专业级Web静默打印
前端·javascript·vue.js·electron·html
RFCEO2 小时前
前端编程 课程十三、:CSS核心基础1:CSS选择器
前端·css·css基础选择器详细教程·css类选择器使用方法·css类选择器命名规范·css后代选择器·精准选中嵌套元素