在 Angular 中使用 Tailwind 制作汉堡菜单的动画

Posted

技术标签:

【中文标题】在 Angular 中使用 Tailwind 制作汉堡菜单的动画【英文标题】:Animate a hamburger menu from Tailwind in Angular 【发布时间】:2021-05-21 06:19:54 【问题描述】:

我在 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- 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- 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.io/guide/transition-and-triggers 在转换期间应该像在特定侦听器上设置类一样简单。 (我不喜欢 Angular,所以无法继续提供帮助) 我更喜欢使用原生角度动画,并与 Tailwind 集成 【参考方案1】:

以下是我将遵循的方法。

    确保导入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 元素

使用state('stateName'定义2个状态在我们上面的例子中,状态名称是openclosed

在状态下,我们使用style( ... )定义样式

我们最终使用transition(...) 定义过渡。这将定义时间和动画样式

更多关于动画Angular animations

    为状态定义一个 getter
get openCloseTrigger() 
  return this.mobileMenuOpen ? "open" : "closed";

    在 HTML 中将状态绑定到 getter
<div [@openClose]="openCloseTrigger" ...> 
  <!-- Other stuff here -->
</div>

一切都应该准备好了,您的菜单应该会根据需要进行动画处理

See this demo on stackblitz

在导航时关闭浏览器 我们可以利用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();
  

See this functionality on stackblitz

【讨论】:

是的,我将整个 trigger 块放在一个新的 ts 文件中以使其可重复使用。 下面是根据stackblitz.com/edit/angular-ivy-99gnub上面的@Pieterjan评论在新文件中提取触发器的示例@ 谢谢,太好了 - 如果用户单击菜单中的项目,我如何关闭菜单?即,如果他们点击主页,他们会前往那里,但菜单保持打开状态。 @欧文凯文 简单设置this.mobileMenuOpen = false; 除了@Pieterjan 的建议外,我们还可以添加NavigationEnd 事件以在用户离开页面时观看。发生这种情况时,我们会致电this.mobileMenuOpen = false。查看更新的解决方案【参考方案2】:

这是一种仅将顺风类用于动画的方法。这是stackblitz demo

这里有一个简短的解释。

最初对于移动菜单div,我们设置了顺风类,使div 处于隐藏状态。为此,我们已经使用了。

scale-95 , opacity-0 我们还使用了pointer-events-none 来避免隐藏状态下的交互。

当菜单处于活动状态时,我们添加以下类。

scale-100opacity-100pointer-events-auto

为了对这些属性进行动画处理,我们在div 上使用了transition 类,并在过渡持续时间中使用了duration-200 类。

    <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- 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- 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> 

所以,只要使用正确的顺风类,就可以实现动画效果。

【讨论】:

以上是关于在 Angular 中使用 Tailwind 制作汉堡菜单的动画的主要内容,如果未能解决你的问题,请参考以下文章

Tailwind 在 Angular 9 中使用自定义 scss 文件进行扩展

Angular 11 中使用 Tailwind CSS

Tailwind 自定义颜色在 Angular 生产构建中不起作用

在 Angular 中从 Typescript 文件配置 Tailwind 主题

如何在 Tailwind 中制作全屏模式

在 Tailwind CSS 中制作动画标签?