在 Angular 中使用 Tailwind 制作汉堡菜单动画
Animate a hamburger menu from Tailwind in Angular
我在 Angular 应用程序中使用 Tailwind UI,可以使用以下命令打开/关闭汉堡菜单
<header>
<div class="-mr-2 -my-2 md:hidden">
<button type="button" (click)="toggleMobileMenu()"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<div class="absolute z-30 top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden" *ngIf="mobileMenuOpen">
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="flex items-center justify-between">
<button (click)="toggleMobileMenu()" type="button"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="py-6 px-5">
<div class="grid gap-4">
<a routerLink="/" class="text-base font-medium text-gray-900 hover:text-gray-700">
Home
</a>
</div>
</div>
</div>
</div>
</header>
toggleMobileMenu() {
this.mobileMenuOpen = !this.mobileMenuOpen;
}
这是一个非常简单的例子。
如何制作动画?
说明是:
Mobile menu, show/hide based on mobile menu state.
Entering: "duration-200 ease-out"
From: "opacity-0 scale-95"
To: "opacity-100 scale-100"
Leaving: "duration-100 ease-in"
From: "opacity-100 scale-100"
To: "opacity-0 scale-95"
而且我不知道如何将其转换为 angular 动画
以下是我会遵循的方法。
- 确保导入
BrowserAnimationsModule
@NgModule({
imports: [ BrowserModule, BrowserAnimationsModule, ... ],
...
})
- 在你的
@Component
装饰器下创建animations
数组如下
@Component({
,,,,
animations: [
trigger("openClose", [
// ...
state(
"open",
style({
opacity: 1,
transform: "scale(1, 1)"
})
),
state(
"closed",
style({
opacity: 0,
transform: "scale(0.95, 0.95)"
})
),
transition("open => closed", [animate("100ms ease-in")]),
transition("closed => open", [animate("200ms ease-out")])
])
]
})
在我们下面包含的动画数组中
trigger("openClose", [ ...])
定义了触发器的名称。这将在 HTML 模板中用于绑定到 dom 元素
define 2 state using state('stateName'
在我们上面的示例中,状态名称是 open
和 closed
在状态下我们使用style({ ... })
定义样式
我们最终使用transition(...)
定义了转换。这将定义时间和动画样式
更多关于动画的内容Angular animations
- 为状态
定义一个getter
get openCloseTrigger() {
return this.mobileMenuOpen ? "open" : "closed";
}
- 将状态绑定到 getter 到 HTML
<div [@openClose]="openCloseTrigger" ...>
<!-- Other stuff here -->
</div>
一切都应该准备就绪,您的菜单应该根据需要设置动画
导航时关闭浏览器
我们可以利用 NavigationEnd
事件来实现此功能。当用户在特定页面上时,他们将不会离开该页面,因此没有 NavigationEnd
。菜单将保持打开状态,但当他们导航到另一页时,将调用 NavigationEnd
事件并且菜单将关闭
这是方法
constructor(private router: Router) {}
navigationEnd$ = this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
tap(() => (this.mobileMenuOpen = false))
);
ngOnInit() {
this.navigationEnd$.subscribe();
}
这是一种仅使用顺风 classes 来制作动画的方法。这是一个stackblitz demo
下面是一个简短的解释。
最初,对于移动菜单 div
,我们设置了顺风 classes,使 div
保持隐藏状态。为此,我们使用了。
scale-95
, opacity-0
并且我们还使用 pointer-events-none
来避免隐藏状态下的交互。
当菜单处于活动状态时,我们添加以下 classes.
scale-100
、opacity-100
和 pointer-events-auto
.
为了使这些属性动起来,我们在 div
上使用了 transition
class,在过渡期间使用了 duration-200
class。
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<header>
<div class="-mr-2 -my-2 md:hidden">
<button type="button" (click)="toggleMobileMenu()"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<!-- here we have added transition transform scale-95 opacity-0 duration-200 pointer-events-none -->
<div class="absolute z-30 top-0 inset-x-0 p-2 transition transform scale-95 opacity-0 duration-200 pointer-events-none md:hidden"
[ngClass]="{'scale-100 pointer-events-auto opacity-100': mobileMenuOpen}">
<!-- then toggle classes scale-100 opacity-100 and pointer-events-auto -->
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="flex items-center justify-between">
<button (click)="toggleMobileMenu()" type="button"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="py-6 px-5">
<div class="grid gap-4">
<a routerLink="/" (click)="toggleMobileMenu()" class="text-base font-medium text-gray-900 hover:text-gray-700">
Home
</a>
</div>
</div>
</div>
</div>
</header>
所以,只要使用正确的顺风classes,就可以实现动画效果。
我在 Angular 应用程序中使用 Tailwind UI,可以使用以下命令打开/关闭汉堡菜单
<header>
<div class="-mr-2 -my-2 md:hidden">
<button type="button" (click)="toggleMobileMenu()"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<div class="absolute z-30 top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden" *ngIf="mobileMenuOpen">
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="flex items-center justify-between">
<button (click)="toggleMobileMenu()" type="button"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="py-6 px-5">
<div class="grid gap-4">
<a routerLink="/" class="text-base font-medium text-gray-900 hover:text-gray-700">
Home
</a>
</div>
</div>
</div>
</div>
</header>
toggleMobileMenu() {
this.mobileMenuOpen = !this.mobileMenuOpen;
}
这是一个非常简单的例子。
如何制作动画?
说明是:
Mobile menu, show/hide based on mobile menu state.
Entering: "duration-200 ease-out"
From: "opacity-0 scale-95"
To: "opacity-100 scale-100"
Leaving: "duration-100 ease-in"
From: "opacity-100 scale-100"
To: "opacity-0 scale-95"
而且我不知道如何将其转换为 angular 动画
以下是我会遵循的方法。
- 确保导入
BrowserAnimationsModule
@NgModule({
imports: [ BrowserModule, BrowserAnimationsModule, ... ],
...
})
- 在你的
@Component
装饰器下创建animations
数组如下
@Component({
,,,,
animations: [
trigger("openClose", [
// ...
state(
"open",
style({
opacity: 1,
transform: "scale(1, 1)"
})
),
state(
"closed",
style({
opacity: 0,
transform: "scale(0.95, 0.95)"
})
),
transition("open => closed", [animate("100ms ease-in")]),
transition("closed => open", [animate("200ms ease-out")])
])
]
})
在我们下面包含的动画数组中
trigger("openClose", [ ...])
定义了触发器的名称。这将在 HTML 模板中用于绑定到 dom 元素define 2 state using
state('stateName'
在我们上面的示例中,状态名称是open
和closed
在状态下我们使用
定义样式style({ ... })
我们最终使用
transition(...)
定义了转换。这将定义时间和动画样式
更多关于动画的内容Angular animations
- 为状态 定义一个getter
get openCloseTrigger() {
return this.mobileMenuOpen ? "open" : "closed";
}
- 将状态绑定到 getter 到 HTML
<div [@openClose]="openCloseTrigger" ...>
<!-- Other stuff here -->
</div>
一切都应该准备就绪,您的菜单应该根据需要设置动画
导航时关闭浏览器
我们可以利用 NavigationEnd
事件来实现此功能。当用户在特定页面上时,他们将不会离开该页面,因此没有 NavigationEnd
。菜单将保持打开状态,但当他们导航到另一页时,将调用 NavigationEnd
事件并且菜单将关闭
这是方法
constructor(private router: Router) {}
navigationEnd$ = this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
tap(() => (this.mobileMenuOpen = false))
);
ngOnInit() {
this.navigationEnd$.subscribe();
}
这是一种仅使用顺风 classes 来制作动画的方法。这是一个stackblitz demo
下面是一个简短的解释。
最初,对于移动菜单 div
,我们设置了顺风 classes,使 div
保持隐藏状态。为此,我们使用了。
scale-95
, opacity-0
并且我们还使用 pointer-events-none
来避免隐藏状态下的交互。
当菜单处于活动状态时,我们添加以下 classes.
scale-100
、opacity-100
和 pointer-events-auto
.
为了使这些属性动起来,我们在 div
上使用了 transition
class,在过渡期间使用了 duration-200
class。
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<header>
<div class="-mr-2 -my-2 md:hidden">
<button type="button" (click)="toggleMobileMenu()"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<!-- here we have added transition transform scale-95 opacity-0 duration-200 pointer-events-none -->
<div class="absolute z-30 top-0 inset-x-0 p-2 transition transform scale-95 opacity-0 duration-200 pointer-events-none md:hidden"
[ngClass]="{'scale-100 pointer-events-auto opacity-100': mobileMenuOpen}">
<!-- then toggle classes scale-100 opacity-100 and pointer-events-auto -->
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="flex items-center justify-between">
<button (click)="toggleMobileMenu()" type="button"
class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="py-6 px-5">
<div class="grid gap-4">
<a routerLink="/" (click)="toggleMobileMenu()" class="text-base font-medium text-gray-900 hover:text-gray-700">
Home
</a>
</div>
</div>
</div>
</div>
</header>
所以,只要使用正确的顺风classes,就可以实现动画效果。