Javascript 如何在Angular work下创建动态清晰上下文菜单(下拉菜单)?

Javascript 如何在Angular work下创建动态清晰上下文菜单(下拉菜单)?,javascript,angular,vmware-clarity,clarity,Javascript,Angular,Vmware Clarity,Clarity,我正在尝试使用Angular下的Clarity UI库动态生成上下文菜单。我找不到“contextmenu”清晰组件,所以我使用了下拉菜单组件-我意识到下拉菜单应该通过连接到按钮来工作,但我不希望它连接到按钮-我希望它作为右键单击菜单,如下所述。(对不起,这篇文章太长了,我只是想确定所有的信息都在那里。) 我这里有一个问题: 在我的主组件中,我有两个SVG圆圈,当我点击它们时,我想显示一个动态生成的上下文菜单(在这个示例中,我只需鼠标左键单击,在我的真实代码中,我有响应右键单击的JointJS节

我正在尝试使用Angular下的Clarity UI库动态生成上下文菜单。我找不到“contextmenu”清晰组件,所以我使用了
下拉菜单
组件-我意识到下拉菜单应该通过连接到按钮来工作,但我不希望它连接到按钮-我希望它作为右键单击菜单,如下所述。(对不起,这篇文章太长了,我只是想确定所有的信息都在那里。)

我这里有一个问题:

在我的主组件中,我有两个SVG圆圈,当我点击它们时,我想显示一个动态生成的上下文菜单(在这个示例中,我只需鼠标左键单击,在我的真实代码中,我有响应右键单击的JointJS节点)

主组件创建“contextMenuInfo”结构,该结构保存鼠标位置信息(用于指定菜单应显示的位置)、指示应显示菜单的布尔值以及指示单击了哪个圆的节点id

<div (mousemove)="onMouseMoved($event)">
  <svg viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
    <circle cx="25" cy="25" r="20" (click)="itemClick(1)" />
    <circle cx="75" cy="25" r="20" (click)="itemClick(2)" />
  </svg>
</div>
<div style="position: absolute" [style.top]="contextMenuInfo.top" [style.left]="contextMenuInfo.left">
    <contextmenu [showContextMenu]="contextMenuInfo.showContextMenu" [nodeId]="contextMenuInfo.nodeId"></contextmenu>
</div>
下面是生成菜单内容的代码。它每5个菜单项任意创建一个子菜单

  menuItems() {
    const list = [];
    list.push(
      { type: 'header', text: 'Heading', id: this.nodeId }
    );
    for (let i = 0; i < 10; ++i) {
      if (i % 5 === 4) {
        list.push(
          { type: 'submenu', text: 'Submenu' + i, id: this.nodeId }
        );
      } else {
        list.push(
          { type: 'item', text: 'MenuItem ' + i, id: this.nodeId, click: this.callback }
        );
      }
    }
    console.log('created menuItems list of size: ' + list.length);
    return list;
  }

  submenuItems(nodeId: number, submenuId: number) {
    const list = [];
    list.push(
      { type: 'header', text: 'Submenu Heading for ' +  submenuId, id: nodeId }
    );
    for (let si = 0; si < 5; ++si) {
      list.push(
        { type: 'item', text: 'SubMenuItem ' + si, id: nodeId, click: this.callback }
      );
    }
    console.log('created submenuItems list nodeId: ' + nodeId + ', submenuId: ' + submenuId + ' of size: ' + list.length);
    return list;
  }

  callback(id: string){
    console.log('item ' + id + ' clicked');
  }
menuItems(){
常量列表=[];
list.push(
{type:'header',text:'Heading',id:this.nodeId}
);
for(设i=0;i<10;++i){
如果(i%5==4){
list.push(
{type:'submenu',text:'submenu'+i,id:this.nodeId}
);
}否则{
list.push(
{type:'item',text:'MenuItem'+i,id:this.nodeId,click:this.callback}
);
}
}
log('created menuItems list of size:'+list.length);
退货清单;
}
子菜单项(节点ID:编号,子菜单ID:编号){
常量列表=[];
list.push(
{type:'header',text:'Submenu Heading for'+submenuId,id:nodeId}
);
对于(设si=0;si<5;++si){
list.push(
{键入:'item',文本:'subnumitem'+si,id:nodeId,单击:this.callback}
);
}
console.log('创建的子菜单项列表nodeId:'+nodeId+',子菜单id:'+subnumuid+',大小为'+list.length');
退货清单;
}
回调(id:string){
log('item'+id+'clicked');
}
以下是我看到的问题:

  • 在主组件中使用showContextMenu布尔值并不好,因为在单击后关闭菜单时,它不会被重置,这意味着每秒钟对圆的“单击”都会被吸收-我不确定正确的方法是什么

  • 对于此stackblitz,上下文菜单实际上不会显示。它看起来会被触发以显示,因为在menuItems()和submenuItems()例程中放置断点表明它们被调用,但实际上没有显示任何内容。我的实际代码似乎显示主菜单ok-抱歉,但我不明白为什么stackblitz没有显示菜单,而我的实际代码显示。一旦为此提供了解决方案,则可能需要回答以下问题的其余部分

  • 下面是我的实际原型应用程序中显示的菜单图片:

  • 我不知道为什么,但是每次单击圆都会调用menuItems()例程两次。在我的实际代码中,我实际上看到,一旦显示菜单,就会多次调用menuItems()例程,特别是在上下文菜单本身上下移动鼠标时(菜单保持显示-只需打开和关闭鼠标)。有没有办法限制调用的次数?最终的应用程序可能需要很长时间来填充菜单,我不希望它被频繁调用

  • 当显示菜单时(在我的实际代码中),单击任何菜单
    似乎会根据需要触发回调,但是整个上下文菜单不会消失(它应该消失,因为
    clrCloseMenuOnItemClick
    设置为true)

  • 单击
    子菜单
    按钮不会使已定义的
    子菜单
    出现-它不起任何作用

  • 谢谢,我感谢你能提供的任何帮助

      menuItems() {
        const list = [];
        list.push(
          { type: 'header', text: 'Heading', id: this.nodeId }
        );
        for (let i = 0; i < 10; ++i) {
          if (i % 5 === 4) {
            list.push(
              { type: 'submenu', text: 'Submenu' + i, id: this.nodeId }
            );
          } else {
            list.push(
              { type: 'item', text: 'MenuItem ' + i, id: this.nodeId, click: this.callback }
            );
          }
        }
        console.log('created menuItems list of size: ' + list.length);
        return list;
      }
    
      submenuItems(nodeId: number, submenuId: number) {
        const list = [];
        list.push(
          { type: 'header', text: 'Submenu Heading for ' +  submenuId, id: nodeId }
        );
        for (let si = 0; si < 5; ++si) {
          list.push(
            { type: 'item', text: 'SubMenuItem ' + si, id: nodeId, click: this.callback }
          );
        }
        console.log('created submenuItems list nodeId: ' + nodeId + ', submenuId: ' + submenuId + ' of size: ' + list.length);
        return list;
      }
    
      callback(id: string){
        console.log('item ' + id + ' clicked');
      }