如何在自定义 Angular 嵌套菜单组件上放置子菜单

问题描述 投票:0回答:1

我创建了一个 Stackblitz (https://stackblitz.com/edit/stackblitz-starters-xxbp1t?file=src%2Fmain.ts) 来演示我的多嵌套菜单的问题,但基本问题是当用户将鼠标悬停在“选项 3”上时,子菜单会正确显示,但位置错误。我怎样才能让子菜单与之前选择的选项一致,如下所示:

html css angular
1个回答
0
投票

您不需要任何角度代码,主要是为了

hiding/showing
,请在下面找到一个使用CSS作为位置的工作示例。如有疑问请告诉我!

家长

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { MenuComponent } from './menu/menu';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [MenuComponent],
  template: `
  <button (click)="buttonClicked($event)">Open Menu</button>
    <app-menu [display]="displayStyle" (menuItemSelected)="displayStyle='none'">
  `,
})
export class App {
  displayStyle = 'none';

  buttonClicked(evt: MouseEvent) {
    evt.stopPropagation();
    if (this.displayStyle === 'block') {
      this.displayStyle = 'none';
    } else {
      this.displayStyle = 'block';
    }
  }
}

bootstrapApplication(App);

菜单ts

// context-menu.component.ts
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';

export interface MenuItem {
  label: string;
  position?: any;
  action?: () => void;
  subItems?: MenuItem[];
  showSubMenu?: boolean; // Property to control submenu visibility
}

@Component({
  selector: 'app-menu',
  templateUrl: './menu.html',
  styleUrls: ['./menu.scss'],
  standalone: true,
  imports: [CommonModule],
})
export class MenuComponent {
  @Input() public display = 'none';
  @Output() public menuItemSelected = new EventEmitter<MenuItem>();
  public menuItems: MenuItem[] = [
    { label: 'Option 1', action: () => this.doSomething('Option 1') },
    {
      label: 'Option 2 Mega thing',
      action: () => this.doSomething('Option 2'),
    },
    {
      label: 'Option 3',
      subItems: [
        {
          label: 'Sub Option 1',
          action: () => this.doSomething('Sub Option 1'),
        },
        {
          label: 'Sub Option 2',
          subItems: [
            {
              label: 'Sub-Sub Option 1',
              action: () => this.doSomething('Sub-Sub Option 1'),
            },
          ],
        },
      ],
    },
  ];

  public onMenuItemClick(event: MouseEvent, item: MenuItem): void {
    this.menuItemSelected.emit(item);
  }

  private doSomething(what: string): void {
    console.log(what);
  }
}

菜单 html

<ng-template
  #recursiveMenu
  let-menuItems="menuItems"
  let-root="root"
  let-display="display"
>
  <div
    class="context-menu"
    [ngClass]="{'child' : !root }"
    [style.display]="display"
  >
    <ul [ngClass]="{'child' : !root }">
      <li
        *ngFor="let item of menuItems"
        (click)="onMenuItemClick($event, item)"
        style="position: relative"
      >
        {{ item.label }}
        <i
          class="expand-icon"
          *ngIf="item.subItems && item.subItems.length > 0 "
        ></i>
        <ng-container *ngIf="item.subItems && item.subItems.length > 0 ">
          <div
            [ngTemplateOutlet]="recursiveMenu"
            [ngTemplateOutletContext]="{menuItems: item.subItems, position: item.position }"
          ></div>
        </ng-container>
      </li>
    </ul>
  </div>
</ng-template>
<div
  [ngTemplateOutlet]="recursiveMenu"
  [ngTemplateOutletContext]="{menuItems: menuItems, root: true, display: display || 'block'}"
></div>

菜单SCSS

.context-menu ul {
  position: absolute;
  z-index: 1000;
  min-width: 150px;
  background-color: white;
  border: 1px solid #ddd;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  padding: 0;
  margin: 0;
  list-style: none;
  list-style-type: none;
}

.context-menu ul li {
  position: relative;
  padding: 10px 20px;
  cursor: pointer;
  background-color: #fff;
}

.context-menu ul li:hover {
  background-color: #f1f1f1;
}

.expand-icon {
  font-size: 1.2em;
  font-weight: bold;
  float: right;
}

.child {
  position: absolute;
  left: 100%;
  top: 0px;
}
.context-menu.child {
  display: none;
}
li:hover > .context-menu.child {
  display: inline;
}

堆栈闪电战

© www.soinside.com 2019 - 2024. All rights reserved.