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

JointJS+Angular5中带端口元素的类式继承实现问题

如何在JointJS + Angular 5中实现带端口元素的类式继承

我来帮你搞定这个问题,你之前的类式继承思路是对的,只是没摸透JointJS基于Backbone的属性配置逻辑——它的核心配置都存在defaults里,而不是直接挂在类实例上。下面给你一步步讲正确的实现方式:

第一步:正确实现基础元素类BasicElement

JointJS的devs.Model是基于Backbone.Model构建的,所有元素的样式、端口、标记都需要通过重写defaults()方法来定义,而不是直接在类上声明属性。同时要记得在构造函数里调用super(),确保父类的初始化逻辑正常执行。

import * as joint from 'jointjs';

class BasicElement extends joint.shapes.devs.Model {
  constructor(attributes?: joint.shapes.devs.Model.Attributes, options?: any) {
    super(attributes, options);
    // 确保端口配置被正确应用到实例
    this.set('ports', this.defaults.ports);
  }

  // 重写defaults方法,定义基础元素的默认配置
  defaults() {
    return {
      ...super.defaults, // 必须继承父类的默认配置
      type: 'app.BasicElement', // 自定义类型标识,JointJS用来识别元素
      markup: `<g class="scalable">
        <rect class="body" rx="5" ry="5" width="120" height="80" />
        <text class="label" x="60" y="40" text-anchor="middle" dominant-baseline="middle"></text>
      </g>`,
      attrs: {
        rect: { fill: '#fff', stroke: '#333', 'stroke-width': 2 },
        text: { fill: '#333', 'font-size': 14 }
      },
      ports: {
        // 定义端口组(样式、位置统一管理)
        groups: {
          'in': {
            position: 'left',
            attrs: {
              circle: { r: 6, fill: '#2ecc71', stroke: '#fff', 'stroke-width': 2 }
            }
          },
          'out': {
            position: 'right',
            attrs: {
              circle: { r: 6, fill: '#e74c3c', stroke: '#fff', 'stroke-width': 2 }
            }
          }
        },
        // 定义具体的端口实例
        items: [
          { id: 'in1', group: 'in' }
        ]
      }
    };
  }
}

第二步:子类继承BasicElement

子类同样通过重写defaults()来扩展基础元素的配置,记得用扩展运算符...继承父类的所有默认配置,再修改或添加自己的内容:

class SomeElement extends BasicElement {
  defaults() {
    return {
      ...super.defaults, // 继承基础元素的所有配置
      type: 'app.SomeElement', // 子类的自定义类型
      attrs: {
        ...super.defaults.attrs, // 继承基础样式
        rect: { ...super.defaults.attrs.rect, fill: '#f39c12' } // 修改背景色
      },
      ports: {
        ...super.defaults.ports, // 继承端口组配置
        items: [
          ...super.defaults.ports.items, // 保留基础的in1端口
          { id: 'out1', group: 'out' }, // 添加自己的输出端口
          { id: 'in2', group: 'in' } // 添加第二个输入端口
        ]
      }
    };
  }
}

第三步:在Angular组件中使用这些元素

在你的Angular组件里,就可以像普通JointJS元素一样创建实例并添加到画布了:

// 假设你已经初始化了graph和paper
const basicElem = new BasicElement({
  position: { x: 100, y: 100 },
  label: '基础元素'
});

const customElem = new SomeElement({
  position: { x: 300, y: 100 },
  label: '自定义元素'
});

this.graph.addCell(basicElem);
this.graph.addCell(customElem);

为什么你之前的代码没生效?

  1. 属性位置错误:你直接在类上声明markup、ports,但JointJS的Model配置都存在defaults里,实例会从这里读取配置,直接声明的类属性不会被识别。
  2. 缺少type属性:JointJS依赖type字段来识别元素类型,没有的话会导致渲染异常。
  3. 端口结构不正确:devs.Model的端口需要完整的groups(样式组)和items(具体端口)结构,单独写inPorts是无效的。

TypeScript类型提示修复

如果遇到TypeScript类型报错(比如Property 'defaults' does not exist on type...),可以添加自定义类型声明来扩展JointJS的类型:

declare module 'jointjs' {
  namespace shapes {
    namespace app {
      class BasicElement extends joint.shapes.devs.Model {}
      class SomeElement extends BasicElement {}
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:14:21