You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular/JS/TypeScript中基于GoJS实现自定义拖拽决策树UI?

GoJS 自定义拖拽决策树UI实现示例

下面是覆盖你需求的完整可运行代码,包含节点增删、链接管理和节点选项功能,关键部分都加了注释:

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/gojs"></script>
  <style>
    #myDiagramDiv { width: 1000px; height: 600px; border: 1px solid #ccc; }
    .button { margin: 5px; padding: 8px; cursor: pointer; background: #eee; border: none; border-radius: 4px; }
  </style>
</head>
<body>
  <div id="myDiagramDiv"></div>
  <div>
    <button class="button" onclick="addNode()">添加节点</button>
    <button class="button" onclick="deleteSelected()">删除选中项</button>
  </div>

  <script>
    var $ = go.GraphObject.make;

    // 初始化画布配置
    var myDiagram = $(go.Diagram, "myDiagramDiv", {
      initialContentAlignment: go.Spot.Center,
      undoManager: true, // 开启撤销/重做,方便操作
      allowDrop: true, // 允许拖拽节点
      // 开启拖拽创建链接功能
      linkingTool: {
        isEnabled: true,
        direction: go.LinkingTool.ForwardsOnly, // 只允许从节点输出端发起链接
        doActivate: function() {
          go.LinkingTool.prototype.doActivate.call(this);
          this.temporaryLink.routing = go.Link.AvoidsNodes; // 临时链接自动避开节点
        }
      },
      // 点击空白处快速创建节点
      clickCreatingTool: {
        archetypeNodeData: { text: "新节点", options: [] }
      }
    });

    // 节点模板定义
    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        {
          movable: true, // 允许拖拽节点
          deletable: true, // 按Delete键可删除节点
          // 右键菜单:用于添加/管理选项
          contextMenu: $(go.Adornment, "Vertical",
            $(go.TextBlock, "添加选项", { margin: 4, cursor: "pointer", click: addOption }),
            $(go.TextBlock, "删除选中选项", { margin: 4, cursor: "pointer", click: deleteSelectedOptions })
          )
        },
        $(go.Shape, "RoundedRectangle", { fill: "#5BC0EB", strokeWidth: 2 }),
        $(go.Panel, "Vertical",
          // 节点标题
          $(go.TextBlock, 
            { margin: 8, font: "bold 14px sans-serif" },
            new go.Binding("text", "text")
          ),
          // 选项列表容器
          $(go.ListBox,
            {
              name: "OPTIONS_LIST",
              itemTemplate: $(go.Panel, "Horizontal",
                $(go.TextBlock, { margin: 4 }, new go.Binding("text")),
                $(go.Shape, "X", { width: 12, height: 12, fill: "#d9534f", margin: 4, cursor: "pointer", click: deleteSingleOption })
              ),
              width: 180,
              height: 100,
              background: "#f8f9fa",
              selectionMode: go.ListBox.Single // 支持单选选项
            },
            new go.Binding("itemArray", "options")
          )
        )
      );

    // 链接模板定义
    myDiagram.linkTemplate =
      $(go.Link,
        {
          deletable: true, // 按Delete键可删除链接
          routing: go.Link.AvoidsNodes, // 链接自动避开节点
          corner: 5 // 链接转角圆角
        },
        $(go.Shape, { strokeWidth: 2 }),
        $(go.Shape, { toArrow: "Standard", stroke: null })
      );

    // 初始化决策树数据
    myDiagram.model = new go.GraphLinksModel(
      [
        { key: 1, text: "根节点", options: ["开始调研", "确认需求"] },
        { key: 2, text: "执行方案A", options: [] },
        { key: 3, text: "执行方案B", options: [] }
      ],
      [
        { from: 1, to: 2 },
        { from: 1, to: 3 }
      ]
    );

    // 按钮触发添加节点
    function addNode() {
      var newKey = myDiagram.model.nodeDataArray.length + 1;
      myDiagram.model.addNodeData({
        key: newKey,
        text: "节点" + newKey,
        options: []
      });
    }

    // 删除选中的节点/链接
    function deleteSelected() {
      var selection = myDiagram.selection;
      if (selection.count === 0) return;
      myDiagram.startTransaction("delete selection");
      selection.each(function(part) {
        if (part instanceof go.Node) {
          myDiagram.model.removeNodeData(part.data);
        } else if (part instanceof go.Link) {
          myDiagram.model.removeLinkData(part.data);
        }
      });
      myDiagram.commitTransaction("delete selection");
    }

    // 右键菜单:给节点添加选项
    function addOption(e, obj) {
      var node = obj.part.adornedPart;
      var input = prompt("请输入选项内容:");
      if (!input) return;
      myDiagram.model.startTransaction("add option");
      var updatedOptions = [...node.data.options, input];
      myDiagram.model.setDataProperty(node.data, "options", updatedOptions);
      myDiagram.commitTransaction("add option");
    }

    // 删除单个选项(点击选项旁的X)
    function deleteSingleOption(e, obj) {
      var item = obj.part;
      var listBox = item.panel;
      var node = listBox.part;
      var index = listBox.items.indexOf(item);
      if (index < 0) return;
      myDiagram.model.startTransaction("delete single option");
      var updatedOptions = [...node.data.options];
      updatedOptions.splice(index, 1);
      myDiagram.model.setDataProperty(node.data, "options", updatedOptions);
      myDiagram.commitTransaction("delete single option");
    }

    // 右键菜单:删除选中的选项
    function deleteSelectedOptions(e, obj) {
      var node = obj.part.adornedPart;
      var listBox = node.findObject("OPTIONS_LIST");
      var selectedItems = listBox.selectedItems;
      if (selectedItems.count === 0) return;
      myDiagram.model.startTransaction("delete selected options");
      var updatedOptions = [...node.data.options];
      // 倒序删除,避免索引偏移
      for (var i = selectedItems.count - 1; i >= 0; i--) {
        var item = selectedItems.elt(i);
        var idx = listBox.items.indexOf(item);
        if (idx >= 0) updatedOptions.splice(idx, 1);
      }
      myDiagram.model.setDataProperty(node.data, "options", updatedOptions);
      myDiagram.commitTransaction("delete selected options");
    }
  </script>
</body>
</html>

功能说明

1. 节点与链接管理

  • 创建链接:拖拽任意节点的边缘到另一个节点,即可自动生成链接;也可以通过点击空白处创建新节点后,拖拽链接到已有节点。
  • 删除链接/节点:选中目标节点或链接,按Delete键,或者点击页面上的「删除选中项」按钮即可删除。
  • 添加节点:点击「添加节点」按钮快速创建,或直接点击画布空白处生成新节点。

2. 节点选项管理

  • 添加选项:右键点击节点,选择「添加选项」,输入内容后确认即可添加到节点的选项列表。
  • 删除选项:点击选项右侧的红色「X」删除单个选项;或右键节点选择「删除选中选项」,先在列表中选中要删除的选项再执行删除。

内容的提问来源于stack exchange,提问作者Margaret Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:00:01