1

我正在尝试使用 Angular 下的 Clarity UI 库动态生成上下文菜单。我找不到'contextmenu' Clarity 组件,所以我正在使用该dropdown组件 - 我意识到下拉菜单应该通过附加到按钮来工作,但我不希望它附加到按钮 - 我想要它作为右键菜单,如下所述。(抱歉这篇文章的长度,我只是想确保所有信息都在那里。)

我在这里遇到问题的 Stackblitz:https ://stackblitz.com/edit/angular-ivy-xsp8ik

在我的主要组件中,我有两个 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>

contextmenu 组件包含应该显示上下文菜单的 html。clr-dropdown-menu 中有三种类型的元素:alabel创建一个菜单标题,一个item应该产生一个带有点击回调的实际菜单按钮,一个submenu应该产生一个嵌套的子菜单。该代码用于*ngFor循环遍历菜单项,以及*ngIf用于测试该项是哪种类型的语句,并将显示相应的内容。

<clr-dropdown class="contextdropdown" [clrCloseMenuOnItemClick]="true">
    <clr-dropdown-menu *clrIfOpen="showContextMenu" class="contextmenudropdown">
        <ng-container *ngFor="let item of menuItems()">
            <label *ngIf="item.type === 'header'" class="dropdown-header">{{item.text}} for node {{item.id}}</label>
            <button *ngIf="item.type === 'item'" type="button" clrDropdownItem
                (click)="item.click(item.text)">{{item.text}} for node {{item.id}}</button>
            <clr-dropdown *ngIf="item.type === 'submenu'">
                <button clrDropdownTrigger>{{item.text}}</button>
                <clr-dropdown-menu class="contextmenudropdown">
                    <ng-container *ngFor="let subitem of submenuItems(item.id, item.text)">
                        <label *ngIf="subitem.type === 'header'" class="dropdown-header">{{subitem.text}} for node
                            {{subitem.id}}</label>
                        <button *ngIf="subitem.type === 'item'" type="button" clrDropdownItem
                            (click)="subitem.click(subitem.text)">{{subitem.text}} for node {{subitem.id}}</button>
                    </ng-container>
                </clr-dropdown-menu>
            </clr-dropdown>
        </ng-container>
    </clr-dropdown-menu>
</clr-dropdown>

这是生成菜单内容的代码。它每 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');
  }

这些是我看到的问题:

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

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

这是在我的实际原型应用程序中显示的菜单图片:

实际应用中显示的主菜单图片

  1. 我不知道为什么,但是每次单击圆圈都会调用 menuItems() 例程两次。在我的实际代码中,我实际上看到,一旦显示菜单,menuItems() 例程就会被调用很多次,尤其是在将鼠标移入和移出上下文菜单本身时(菜单保持显示 - 只需将鼠标移开和移开离开)。有没有办法限制调用的次数?最终的应用程序可能会花费大量时间来填充菜单,我不希望它被如此频繁地调用。

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

  3. 单击submenu按钮不会使定义submenu出现 - 它什么也不做。

谢谢,感谢您提供的任何帮助。

4

0 回答 0