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);
为什么你之前的代码没生效?
- 属性位置错误:你直接在类上声明
markup、ports,但JointJS的Model配置都存在defaults里,实例会从这里读取配置,直接声明的类属性不会被识别。 - 缺少
type属性:JointJS依赖type字段来识别元素类型,没有的话会导致渲染异常。 - 端口结构不正确:
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
相关产品推荐
相关产品推荐

