깜놀하는 해므찌로

Ionic Angular mobile side Menu / 아이오닉 앵귤러 모바일 사이드 메뉴 구현 예시 / ionic menu / ion-menu 본문

IT

Ionic Angular mobile side Menu / 아이오닉 앵귤러 모바일 사이드 메뉴 구현 예시 / ionic menu / ion-menu

agnusdei1207 2023. 7. 11. 19:04
반응형
SMALL

메뉴 아이콘
버튼을 누르면 메뉴가 쓰윽~ 하고 측면에서 나타납니다.

0. 실제 서비스 개발중인 앱이라 보안상 가린점 양해부탁드립니다.

참고

https://ionicframework.com/docs/api/menu

 

ion-menu | Ionic Documentation

ion-menu: API Framework Docs for Types of Menu Components

ionicframework.com

 

<main class="flex w-screen h-screen">
  <ion-content
    #content
    id="main" // ion-menu 태그의 contentId 와 일치해야 합니다.
    style="width: 100%; height: 100%"
    [scrollEvents]="true"
    (ionScroll)="ionScroll($event)"
  >
    <!-- flex -->
    <div class="flex flex-col w-full h-full">
      <!-- header -->
      <app-header class="fixed z-40 w-full" (menu)="menu.open()" />
      <!-- content -->
      <router-outlet (activate)="onActivate($event)"></router-outlet>
      <!-- footer-->
      <app-footer class="z-10 w-full" />
    </div>
  </ion-content>

	<!-- 모바일 메뉴 -->
  <ion-menu contentId="main" side="end">
    <div class="h-full bg-neutral-950">
      <div
        class="flex items-center justify-between p-4 border-b border-neutral-950"
      >
        <img style="width: 6.25rem" src="assets/logo/smart_solution.svg" />
        <app-icon
          class="w-6 h-6 text-white"
          name="heroicons:x-mark"
          (click)="menu.close()"
        />
      </div>
      <div
        *ngFor="let menu of menus; last as isLast"
        class="p-2 px-4 py-5 text-white rounded-md border-white/5"
        [class.border-b]="!isLast"
        (click)="handleMenu(menu)"
      >
        {{ menu.data?.['label'] }}
      </div>
    </div>
  </ion-menu>
</main>

 

1. ion-menu 태그를 사용해야합니다. (현재 레이아웃 템플릿)

2. contentId : 반드시 명시해야 하며 어떤 ion-content 에 해당 메뉴를 걸지 결정합니다. id 서로 동일해야 합니다.

(셋팅에 따라 다릅니다.)

 

 

 

@ViewChild(IonMenu) menu!: IonMenu; // 메뉴 핸들링을 위해 선언


handleMenu(menu: Route) { // 메뉴안의 메뉴 클릭 시 해당 페이지로 이동할 수 있도록 메소드 선언
    if (!menu) {
      return;
    }
    this.router.navigateByUrl(menu.path!);
    this.menu.close();
  }

3. 메소드 연결 (레이아웃 컴포넌트)

 

 

메뉴 아이콘

<!-- tablet, mobile -->
      <div class="flex py-4 gap-7 sm:gap-10 md:hidden">
        <div class="relative flex flex-col w-full h-full lg:hidden">
          <app-icon
            src="assets\icon\menu.svg"
            class="w-6 h-6 transition-all active:scale-90 active:text-gray-400"
            [ngClass]="isScrollMoved ? 'text-gray-800' : 'text-white'"
            alt="모바일 메뉴 아이콘"
            (click)="menu.emit()"
          />
        </div>
      </div>

4. 위 이미지를 구현한 메뉴 아이콘 템플릿입니다. (헤더 템플릿)

5. 클릭 이벤트가 발동하면 emit 하여 레이아웃에게 메뉴를 클릭했다는 것을 알립니다.

 

 

  @Output() menu = new EventEmitter<void>(); // 데이터 전달을 위해 eventEmitter 선언
  // 전달할 데이터는 없고 단순히 해당 버튼을 클릭했다는 사실만을 알려주기 위해 void 설정

6. 헤더 컴포넌트에서는 단순히 선언만 합니다.

 

<main class="flex w-screen h-screen">
  <ion-content
    #content
    id="main" 
    style="width: 100%; height: 100%"
    [scrollEvents]="true"
    (ionScroll)="ionScroll($event)"
  >
    <!-- flex -->
    <div class="flex flex-col w-full h-full">
      <!-- header -->
      <app-header class="fixed z-40 w-full" (menu)="menu.open()" /> --> 헤더 컴포넌트에 선언한 eventEmitter
      <!-- content -->
      <router-outlet (activate)="onActivate($event)"></router-outlet>
      <!-- footer-->
      <app-footer class="z-10 w-full" />
    </div>
  </ion-content>

	<!-- 모바일 메뉴 -->
  <ion-menu contentId="main" side="end">
    <div class="h-full bg-neutral-950">
      <div
        class="flex items-center justify-between p-4 border-b border-neutral-950"
      >
        <img style="width: 6.25rem" src="assets/logo/smart_solution.svg" />
        <app-icon // X 모양 아이콘
          class="w-6 h-6 text-white"
          name="heroicons:x-mark"
          (click)="menu.close()" // 메뉴 끄기
        />
      </div>
      <div
        *ngFor="let menu of menus; last as isLast"
        class="p-2 px-4 py-5 text-white rounded-md border-white/5"
        [class.border-b]="!isLast"
        (click)="handleMenu(menu)"
      >
        {{ menu.data?.['label'] }}
      </div>
    </div>
  </ion-menu>
</main>

7. 그럼 다시 레이아웃 템플릿으로 돌아가서, 헤더 컴포넌트에서 선언한 menu 이벤트가 발동하면 menu.open() 을 실행하도록 메소드를 연결합니다.

8. 여기서 menu.open() 메소드는 ionic 내장함수입니다.

 

ion-menu {
  @media (min-width: 360px) {
    &::part(container) {
      width: 100%;
    }
  }
  @media (min-width: 640px) {
    &::part(container) {
      width: 22.5rem;
    }
  }
}

9. 아이오닉 메뉴 sCSS

 

 

/* Core CSS required for Ionic components to work properly */
@import '@ionic/angular/css/core.css';

/* Basic CSS for apps built with Ionic */
@import '@ionic/angular/css/normalize.css';
@import '@ionic/angular/css/structure.css';
@import '@ionic/angular/css/typography.css';
@import '@ionic/angular/css/display.css';

/* Optional CSS utils that can be commented out */
@import '@ionic/angular/css/padding.css';
@import '@ionic/angular/css/float-elements.css';
@import '@ionic/angular/css/text-alignment.css';
@import '@ionic/angular/css/text-transformation.css';
@import '@ionic/angular/css/flex-utils.css';

10. ionic/angular 기본 css

 

 

import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import {
  provideRouter,
  withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { appRoutes } from './app.routes';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { HttpInterceptorImpl } from './interceptors/http-interceptor'; // interceptor
import { NgxsModule } from '@ngxs/store'; // store
import { AdminStore } from './store/auth.store'; // store
import { IonicModule } from '@ionic/angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
    importProvidersFrom(
      HttpClientModule,
      NgxsModule.forRoot([AdminStore]),
      IonicModule.forRoot()
    ),
    { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorImpl, multi: true },
  ],
};

11. app.config providers 에IonModule 명시하기

반응형
LIST