Angular & TailwindCSS - 下拉菜单
Angular & TailwindCSS - Dropdown menu
抱歉,如果之前有人回答过这个问题,但我已经搜索了几天以找到答案,但我还没有找到对我的设置有意义的解决方案(也许我的设置有误,让我们找到出)。
我想使用 Angular 和 Tailwind CSS 创建一个下拉菜单,我的组件 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>
对于菜单按钮,我创建了一个带有选择器的指令 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'}`)
}
}
如果到目前为止我的想法是有道理的,那么在另一个指令中处理 EventEmitter 并将其放在链接的 下拉列表中是否更有意义 div.该指令将使用 HostBinding 应用 css 来设置 opacity-0
和 opacity-100
之间 div 的不透明度,无论 isOpen
是否 true 或 false?
如果这种方法有效,我不确定我将如何在第二个指令中侦听来自第一个指令的事件。
如果我完全不对,有没有人有解决方案可以帮助我理解工作流程?
谢谢!
我想以这种方式写下我的问题有助于我想出一个解决方案。如果有人有办法改进我的代码,请随时 post 其他可以完成的方法:)
我的解决方案:
//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'}`)
}
}
抱歉,如果之前有人回答过这个问题,但我已经搜索了几天以找到答案,但我还没有找到对我的设置有意义的解决方案(也许我的设置有误,让我们找到出)。
我想使用 Angular 和 Tailwind CSS 创建一个下拉菜单,我的组件 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>
对于菜单按钮,我创建了一个带有选择器的指令 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'}`)
}
}
如果到目前为止我的想法是有道理的,那么在另一个指令中处理 EventEmitter 并将其放在链接的 下拉列表中是否更有意义 div.该指令将使用 HostBinding 应用 css 来设置 opacity-0
和 opacity-100
之间 div 的不透明度,无论 isOpen
是否 true 或 false?
如果这种方法有效,我不确定我将如何在第二个指令中侦听来自第一个指令的事件。
如果我完全不对,有没有人有解决方案可以帮助我理解工作流程?
谢谢!
我想以这种方式写下我的问题有助于我想出一个解决方案。如果有人有办法改进我的代码,请随时 post 其他可以完成的方法:)
我的解决方案:
//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'}`)
}
}