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

Angular中无jQuery创建动态DOM元素并传入jsPlumb的实现方案

我来帮你解决这个问题,不用jQuery完全可以用Angular原生方式实现,分两种情况给你详细方案:

一、创建原生DOM元素(替代jQuery方案)

你可以直接用原生JavaScript的document.createElement,或者更符合Angular最佳实践的Renderer2来创建DOM元素,完全不需要依赖jQuery。

方案1:原生JavaScript API

直接用浏览器原生方法创建元素并组装,代码逻辑和jQuery版本完全对应:

["Custom", { 
  create: function(component) { 
    // 创建select元素
    const select = document.createElement('select');
    select.id = 'myDropDown';
    
    // 创建第一个option
    const optionFoo = document.createElement('option');
    optionFoo.value = 'foo';
    optionFoo.textContent = 'foo';
    select.appendChild(optionFoo);
    
    // 创建第二个option
    const optionBar = document.createElement('option');
    optionBar.value = 'bar';
    optionBar.textContent = 'bar';
    select.appendChild(optionBar);
    
    return select;
  }, 
  location: 0.5, 
  id: "customOverlay" 
}]

方案2:Angular Renderer2(推荐)

Renderer2是Angular提供的抽象层,兼容不同平台(比如Web、Server Side Rendering),更符合Angular的设计理念。首先在组件类中注入Renderer2,然后使用它来创建元素:

// 先在组件构造函数中注入Renderer2
constructor(private renderer: Renderer2) {}

// 然后编写覆盖层的create函数
["Custom", { 
  create: (component) => { 
    const select = this.renderer.createElement('select');
    this.renderer.setAttribute(select, 'id', 'myDropDown');
    
    const optionFoo = this.renderer.createElement('option');
    this.renderer.setAttribute(optionFoo, 'value', 'foo');
    this.renderer.setProperty(optionFoo, 'textContent', 'foo');
    this.renderer.appendChild(select, optionFoo);
    
    const optionBar = this.renderer.createElement('option');
    this.renderer.setAttribute(optionBar, 'value', 'bar');
    this.renderer.setProperty(optionBar, 'textContent', 'bar');
    this.renderer.appendChild(select, optionBar);
    
    return select;
  }, 
  location: 0.5, 
  id: "customOverlay" 
}]
二、挂载自定义Angular组件到jsPlumb覆盖层

要把Angular组件作为覆盖层,核心是让Angular编译并挂载组件,然后把组件的宿主DOM元素交给jsPlumb。这里需要用到Angular的组件工厂API(或者独立组件的createComponent方法),同时要注意组件的销毁,避免内存泄漏。

非独立组件(Angular <14 或未使用standalone)

  1. 首先确保你的CustomOverlayComponent在模块中被声明并添加到entryComponents(Angular 9+ Ivy模式下entryComponents可以省略,但保险起见还是加上)。
  2. 在组件类中注入ComponentFactoryResolver、ApplicationRef和Injector:
constructor(
  private componentFactoryResolver: ComponentFactoryResolver,
  private appRef: ApplicationRef,
  private injector: Injector
) {}
  1. 编写覆盖层的create函数:
["Custom", { 
  create: (component) => { 
    // 1. 创建组件工厂
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(CustomOverlayComponent);
    
    // 2. 创建组件实例
    const componentRef = componentFactory.create(this.injector);
    
    // 3. 把组件附加到Angular应用中,触发变更检测
    this.appRef.attachView(componentRef.hostView);
    
    // 4. 获取组件的宿主DOM元素
    const domElement = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
    
    // 可选:给组件传递输入属性
    // componentRef.instance.someInputProperty = '你需要的值';
    
    // 可选:监听组件的输出事件
    // componentRef.instance.someOutputEvent.subscribe((data) => {
    //   console.log('组件输出:', data);
    // });
    
    // 5. 关键:在连接断开时销毁组件,避免内存泄漏
    jsPlumb.on('connectionDetached', (conn) => {
      if (conn.getOverlay('customOverlay')?.component === component) {
        this.appRef.detachView(componentRef.hostView);
        componentRef.destroy();
      }
    });
    
    return domElement;
  }, 
  location: 0.5, 
  id: "customOverlay" 
}]

独立组件(Angular 14+)

如果你的CustomOverlayComponent是标记为standalone: true的独立组件,代码会更简洁,不需要ComponentFactoryResolver:

// 组件类中注入ApplicationRef
constructor(private appRef: ApplicationRef) {}

// 覆盖层create函数
["Custom", { 
  create: (component) => { 
    // 1. 创建组件实例
    const componentRef = createComponent(CustomOverlayComponent, {
      environmentInjector: this.appRef.injector
    });
    
    // 2. 附加到应用中
    this.appRef.attachView(componentRef.hostView);
    
    // 3. 获取宿主DOM元素
    const domElement = componentRef.location.nativeElement;
    
    // 4. 传递输入/监听输出(和非独立组件一致)
    // componentRef.instance.someInput = 'test';
    
    // 5. 监听连接销毁,清理组件
    jsPlumb.on('connectionDetached', (conn) => {
      if (conn.getOverlay('customOverlay')?.component === component) {
        this.appRef.detachView(componentRef.hostView);
        componentRef.destroy();
      }
    });
    
    return domElement;
  }, 
  location: 0.5, 
  id: "customOverlay" 
}]

注意事项

  • 组件销毁:一定要在连接断开时调用componentRef.destroy(),否则会导致内存泄漏,Angular无法回收组件实例。
  • 变更检测:把组件附加到ApplicationRef后,Angular会自动处理变更检测,组件的输入输出都能正常工作。
  • 样式适配:自定义组件的样式可能需要调整,确保它能正确显示在jsPlumb的连接线上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:22:02