简体   繁体   English

Angular & TailwindCSS - 下拉菜单

[英]Angular & TailwindCSS - Dropdown menu

Apologies if this has been answered before, but I have been searching for a couple of days to find an answer and I have not come across a solution that makes sense for my setup (perhaps my setup is wrong, let find out).抱歉,如果之前已经回答过这个问题,但我已经搜索了几天来找到答案,但我没有遇到对我的设置有意义的解决方案(也许我的设置有误,让我们找出答案)。

I would like to create a dropdown menu using Angular with Tailwind CSS, My component html is as follows:我想使用带有 Tailwind CSS 的 Angular 创建一个下拉菜单,我的组件 html 如下:

// recipe-details.component.html
<div>
  <div *ngIf="selectedRecipe;else noRecipe">
    <div class="flex items-center justify-between">
      <h3 class="text-title">{{ selectedRecipe.name }}</h3>

      <!-- The dropdown menu -->
      <div class="relative">

        <!-- The dropdown button -->
        <a href="#" class="bg-green-500 px-3 py-2 rounded-md shadow font-bold text-white flex items-center" appDropdown>Manage recipe
          <svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
            xmlns="http://www.w3.org/2000/svg">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
          </svg></a>

          <!-- Dropdown list of links -->
          <div class="origin-top-right absolute right-0 w-full rounded mt-2 shadow-lg border-gray-800">
            <div class="bg-white py-2">
              <a href="#" class="block px-4 py-2 font-bold text-sm text-gray-700 hover:bg-gray-100">Edit Recipe</a>
              <a href="#" class="block px-4 py-2 font-bold text-sm text-gray-700 hover:bg-gray-100">Delete Recipe</a>
            </div>
          </div>

      </div>

    </div>
    <p>{{ selectedRecipe.description }}</p>
  </div>

  <ng-template #noRecipe>
    <div class="">
      <div class="text-title ">Choose a recipe</div>
      <p>Please choose a recipe from the recipe list.</p>
    </div>
  </ng-template>
</div>

For the menu button I have created a directive with selector appDropdown :对于菜单按钮,我创建了一个带有选择器appDropdown的指令:

//dropdown.directive.ts
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';

@Directive({
  selector: '[appDropdown]'
})
export class DropdownDirective {
  @Output() isMenuOpen = new EventEmitter<boolean>();
  isOpen: boolean = false;

  constructor() { }

  @HostListener('click') toggleMenu() {
    this.isOpen = !this.isOpen;
    this.isMenuOpen.emit(this.isOpen);
    console.log(`Menu status changed. Menu is now ${this.isOpen ? 'Open' : 'Closed'}`)
  }

}

If my way of thinking so far makes sense, does it make further sense to handle the EventEmitter in another directive and place it on the dropdown list of links div .如果到目前为止我的思维方式有意义,那么在另一个指令中处理 EventEmitter 并将其放在链接 div下拉列表中是否更有意义。 The directive would use a HostBinding to apply css to set the opacity of the div between opacity-0 and opacity-100 whether isOpen is true or false ?该指令将使用 HostBinding 应用 css 来设置 div 在opacity-0opacity-100之间的opacity-0 opacity-100无论isOpentrue还是false

If this approach works, I am not sure how I would listen for the Event from the first directive within the second directive.如果这种方法有效,我不确定如何从第二个指令中的第一个指令监听事件。

If I am completely off the mark, does anyone have a solution that would help me understand the workflow?如果我完全偏离目标,是否有人有解决方案可以帮助我理解工作流程?

Thanks!谢谢!

I guess writing my question down this way helped me come up with a solution.我想以这种方式写下我的问题有助于我想出一个解决方案。 If anyone has a way to improve my code, feel free to post other ways it can be done :)如果有人有办法改进我的代码,请随时发布其他可以完成的方法:)

My solution:我的解决方案:

//recipe-detail.component.html
<div>
  <div *ngIf="selectedRecipe;else noRecipe">
    <div class="flex items-center justify-between">
      <h3 class="text-title">{{ selectedRecipe.name }}</h3>
      <div class="relative">
        <a href="#" class="bg-green-500 px-3 py-2 rounded-md shadow font-bold text-white flex items-center" (isMenuOpen)=toggleVisible($event) appDropdown>Manage recipe
          <svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
            xmlns="http://www.w3.org/2000/svg">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
          </svg></a>
          <div class="origin-top-right absolute right-0 w-full rounded mt-2 shadow-lg border-gray-800" [ngClass]="visibilityClasses">
            <div class="bg-white py-2">
              <a href="#" class="block px-4 py-2 font-bold text-sm text-gray-700 hover:bg-gray-100">Edit Recipe</a>
              <a href="#" class="block px-4 py-2 font-bold text-sm text-gray-700 hover:bg-gray-100">Delete Recipe</a>
            </div>
          </div>
      </div>
    </div>
    <p>{{ selectedRecipe.description }}</p>
  </div>

  <ng-template #noRecipe>
    <div class="">
      <div class="text-title ">Choose a recipe</div>
      <p>Please choose a recipe from the recipe list.</p>
    </div>
  </ng-template>
</div>
//recipe-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { Recipe } from 'src/app/models/models.i';
import { RecipeService } from '../../../services/recipes/recipe.service'

@Component({
  selector: 'app-recipe-detail',
  templateUrl: './recipe-detail.component.html',
  styleUrls: ['./recipe-detail.component.scss']
})
export class RecipeDetailComponent implements OnInit {
  selectedRecipe: Recipe;
  visibilityClasses: {};
  private isVisible: boolean = false;

  constructor(private recipeService: RecipeService) { }

  ngOnInit(): void {
    this.recipeService.currentRecipe.subscribe(recipe => this.selectedRecipe = recipe
    );
    this.setVisibilityClasses();
  }

  toggleVisible(isVisible: boolean): void {
    console.log(`is the menu open: ${isVisible ? 'Yes' : 'No'}`)
    this.isVisible = isVisible;
    this.setVisibilityClasses();
  }

  private setVisibilityClasses(): void {
    this.visibilityClasses = {
      'opacity-0': !this.isVisible,
      'opacity-100': this.isVisible
    };
  }
}
//dropdown.directive.ts
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';

@Directive({
  selector: '[appDropdown]'
})
export class DropdownDirective {
  @Output() isMenuOpen = new EventEmitter<boolean>();
  isOpen: boolean = false;

  constructor() { }

  @HostListener('click') toggleMenu() {
    this.isOpen = !this.isOpen;
    this.isMenuOpen.emit(this.isOpen);
    console.log(`Menu status changed. Menu is now ${this.isOpen ? 'Open' : 'Closed'}`)
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM