در اینجا توسط کامپوننت sidenav، کار نمایش لیست تماسها صورت میگیرد و نمایش این کامپوننت واکنشگرا است. به این معنا که در اندازههای صفحات نمایشی بزرگ، نمایان است و در صفحات نمایشی کوچک، مخفی خواهد شد. در بالای صفحه یک Toolbar قرار دارد که همیشه نمایان است و از آن برای نمایش گزینههای منوی برنامه استفاده میکنیم. همچنین ناحیهی main content را هم مشاهده میکنید که با انتخاب هر شخص از لیست تماسها، جزئیات او در این قسمت نمایش داده خواهد شد.
ایجاد ماژول مدیریت تماسها
در قسمت اول، برنامه را به همراه تنظیمات ابتدایی مسیریابی آن ایجاد کردیم که نتیجهی آن تولید فایل src\app\app-routing.module.ts میباشد:
ng new MaterialAngularClient --routing
ng g m ContactManager -m app.module --routing
این دستور ماژول جدید contact-manager را به همراه تنظیمات ابتدایی مسیریابی و همچنین به روز رسانی app.module، برای درج آن، ایجاد میکند. البته در این حالت نیاز است به app.module.ts مراجعه کرد و محل درج آنرا تغییر داد:
import { ContactManagerModule } from "./contact-manager/contact-manager.module"; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule, CoreModule, SharedModule.forRoot(), ContactManagerModule, AppRoutingModule ], }) export class AppModule { }
سپس دستور زیر را اجرا میکنیم تا کامپوننت contact-manager-app در ماژول contact-manager ایجاد شود:
ng g c contact-manager/ContactManagerApp --no-spec
CREATE src/app/contact-manager/contact-manager-app/contact-manager-app.component.html (38 bytes) CREATE src/app/contact-manager/contact-manager-app/contact-manager-app.component.ts (319 bytes) CREATE src/app/contact-manager/contact-manager-app/contact-manager-app.component.css (0 bytes) UPDATE src/app/contact-manager/contact-manager.module.ts (436 bytes)
این کامپوننت به عنوان میزبان سایر کامپوننتهایی که در مقدمهی بحث عنوان شدند، عمل میکند. این کامپوننتها را به صورت زیر در پوشهی components ایجاد میکنیم:
ng g c contact-manager/components/toolbar --no-spec ng g c contact-manager/components/main-content --no-spec ng g c contact-manager/components/sidenav --no-spec
تنظیمات مسیریابی برنامه
در ادامه به src\app\app-routing.module.ts مراجعه کرده و این ماژول جدید را به صورت lazy load معرفی میکنیم:
import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; const routes: Routes = [ { path: "contactmanager", loadChildren: "./contact-manager/contact-manager.module#ContactManagerModule" }, { path: "", redirectTo: "contactmanager", pathMatch: "full" }, { path: "**", redirectTo: "contactmanager" } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
سپس تنظیمات مسیریابی ماژول مدیریت تماسها را در فایل src\app\contact-manager\contact-manager-routing.module.ts به صورت زیر تغییر میدهیم:
import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { MainContentComponent } from "./components/main-content/main-content.component"; import { ContactManagerAppComponent } from "./contact-manager-app/contact-manager-app.component"; const routes: Routes = [ { path: "", component: ContactManagerAppComponent, children: [ { path: "", component: MainContentComponent } ] }, { path: "**", redirectTo: "" } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class ContactManagerRoutingModule { }
کامپوننت ContactManagerApp که کار هاست سایر کامپوننتهای این ماژول را بر عهده دارد، دارای router-outlet خاص خود خواهد بود. به همین جهت برای آن children تعریف شدهاست که مسیر پیشفرض آن، بارگذاری کامپوننت MainContent است.
بنابراین نیاز است به فایل contact-manager-app\contact-manager-app.component.html مراجعه و ابتدا منوی کنار صفحه را به آن افزود:
<app-sidenav></app-sidenav>
سپس در قالب sidenav\sidenav.component.html، کار تعریف toolbar و همچنین router-outlet را انجام میدهیم:
<app-toolbar></app-toolbar> <router-outlet></router-outlet>
معرفی Angular Material به ماژول جدید مدیریت تماسها
در قسمت اول، یک فایل material.module.ts را ایجاد کردیم که به همراه تعریف تمامی کامپوننتهای Angular Material بود. سپس آنرا به shared.module.ts افزودیم که حاوی تعریف ماژول فرمها و همچنین Flex Layout نیز هست. به همین جهت برای معرفی اینها به این ماژول جدید تنها کافی است در فایل src\app\contact-manager\contact-manager.module.ts در قسمت imports، کار معرفی SharedModule صورت گیرد:
import { SharedModule } from "../shared/shared.module"; @NgModule({ imports: [ CommonModule, SharedModule, ContactManagerRoutingModule ] }) export class ContactManagerModule { }
پس از اجرای برنامه مشاهده میکنید که ابتدا ماژول مدیریت تماسها بارگذاری شدهاست و سپس contact-manager-app عمل و sidenav را بارگذاری کرده و آن نیز سبب نمایش کامپوننت toolbar و سپس main-content شدهاست.
تنظیم طرحبندی برنامه توسط کامپوننتهای Angular Material و همچنین Flex Layout
پس از این تنظیمات اکنون نوبت به تنظیم طرحبندی برنامهاست و آنرا با قراردادن کامپوننت Sidenav بستهی Angular Material شروع میکنیم:
<mat-sidenav-container *ngIf="shouldRun"> <mat-sidenav mode="side" opened> Sidenav content </mat-sidenav> Primary content </mat-sidenav-container>
- Over: قسمت Sidenav content بر روی Primary content قرار میگیرد.
- Push: قسمت Sidenav content قسمت Primary content را از سر راه خود بر میدارد.
- Side: قسمت Sidenav content در کنار Primary content قرار میگیرد.
در اینجا از حالت Side، در صفحات نمایشی بزرگ (اولین تصویر این قسمت) و از حالت Over، در صفحات نمایشی موبایل (مانند تصویر زیر) استفاده خواهیم کرد.
در ابتدا کدهای کامل هر سه کامپوننت و سپس توضیحات آنها را مشاهده خواهید کرد:
تنظیم margin در CSS اصلی برنامه
زمانیکه sidenav و toolbar را بر روی صفحه قرار میدهیم، فاصلهای بین آنها و لبههای صفحه مشاهده میشود. برای اینکه این فاصله را به صفر برسانیم، به فایل src\styles.css مراجعه کرده و margin بدنهی صفحه را به صفر تنظیم میکنیم:
@import "~@angular/material/prebuilt-themes/indigo-pink.css"; body { margin: 0; }
طراحی قالب main content
<mat-card> <h1>Main content</h1> </mat-card>
sidenav\sidenav.component.css | sidenav\sidenav.component.html |
.app-sidenav-container { position: fixed; } .app-sidenav { width: 240px; } .wrapper { margin: 50px; } | <mat-sidenav-container fxLayout="row" fxFill> <mat-sidenav #sidenav fxFlex="1 1 100%" [opened]="!isScreenSmall" [mode]="isScreenSmall ? 'over' : 'side'"> <mat-toolbar color="primary"> Contacts </mat-toolbar> <mat-list> <mat-list-item>Item 1</mat-list-item> <mat-list-item>Item 2</mat-list-item> <mat-list-item>Item 3</mat-list-item> </mat-list> </mat-sidenav> <mat-sidenav-content fxLayout="column" fxFlex="1 1 100%" fxFill> <app-toolbar (toggleSidenav)="sidenav.toggle()"></app-toolbar> <div> <router-outlet></router-outlet> </div> </mat-sidenav-content> </mat-sidenav-container> |
- نمای کلی صفحه در این قسمت طراحی شدهاست. sidenav-container که در برگیرندهی اصلی است، به fxLayout از نوع row تنظیم شدهاست. یعنی mat-sidenav و mat-sidenav-content دو ستون آنرا از چپ به راست تشکیل میدهند و درون یک ردیف، سیلان خواهند یافت. همچنین میخواهیم این container کل صفحه را پر کند، به همین جهت از fxFill استفاده شدهاست. این fxFill اعمال شدهی به container، زمانی عمل خواهد کرد که position آن در css، به fixed تنظیم شود که اینکار در css این قالب و در کلاس app-sidenav-container آن انجام شدهاست.
- سپس toolbar و همچنین router-outlet که main content را نمایش میدهند، داخل sidenav-content قرار گرفتهاند و هر دو با هم، ستون دوم این طرحبندی را تشکیل میدهند. به همین جهت fxLayout آن به column تنظیم شدهاست (ستون اول آن، لیست تماسها است و ستون دوم آن، از دو ردیف toolbar و main-content تشکیل میشود).
- اگر دقت کنید یک template reference variable به نام sidenav# به container اعمال شدهاست. از آن، جهت باز و بسته کردن sidenav استفاده میشود:
<app-toolbar (toggleSidenav)="sidenav.toggle()"></app-toolbar>
- mat-sidenav از دو قسمت تشکیل شدهاست. بالای آن توسط mat-toolbar صرفا کلمهی Contacts نمایش داده میشود و سپس ذیل آن، لیست فرضی تماسها توسط کامپوننت mat-list قرار گرفتهاند (تا فعلا خالی نباشد. در قسمتهای بعدی آنرا پویا خواهیم کرد). رنگ تولبار آنرا ("color="primary) نیز به primary تنظیم کردهایم تا خاکستری پیشفرض آن نباشد.
- کار کلاس mat-elevation-z10 این است که بین sidenav و main-content یک سایهی سه بعدی را ایجاد کند که آنرا در تصاویر مشاهده میکنید. عددی که پس از z قرار میگیرد، میزان عمق سایه را مشخص میکند.
- این قسمت از sidenav به همراه دو خاصیت opened و همچنین mode است که به مقدار isScreenSmall عکس العمل نشان میدهند:
<mat-sidenav [opened]="!isScreenSmall" [mode]="isScreenSmall ? 'over' : 'side'">
محتویات فایل sidenav\sidenav.component.ts:
import { Component, OnDestroy, OnInit } from "@angular/core"; import { MediaChange, ObservableMedia } from "@angular/flex-layout"; import { Subscription } from "rxjs"; @Component({ selector: "app-sidenav", templateUrl: "./sidenav.component.html", styleUrls: ["./sidenav.component.css"] }) export class SidenavComponent implements OnInit, OnDestroy { isScreenSmall = false; watcher: Subscription; constructor(private media: ObservableMedia) { this.watcher = media.subscribe((change: MediaChange) => { this.isScreenSmall = change.mqAlias === "xs"; }); } ngOnInit() { } ngOnDestroy() { this.watcher.unsubscribe(); } }
تاثیر خاصیت isScreenSmall بر روی دو خاصیت opened و mode کامپوننت sidenav را در دو تصویر زیر مشاهده میکنید. اگر اندازهی صفحه کوچک شود، ابتدا sidenav مخفی میشود. اگر کاربر بر روی دکمهی منوی همبرگری کلیک کند، سبب نمایش مجدد sidenav، اینبار با حالت over و بر روی محتوای زیرین آن خواهد شد:
طراحی نوار ابزار واکنشگرا
کدهای قالب و css تولبار (ستون دوم طرحبندی کلی صفحه) را در ادامه مشاهده میکنید:
toolbar\toolbar.component.css | toolbar\toolbar.component.html |
.sidenav-toggle { padding: 0; margin: 8px; min-width:56px; } | <mat-toolbar color="primary"> <button mat-button fxHide fxHide.xs="false" class="sidenav-toggle" (click)="toggleSidenav.emit()"> <mat-icon>menu</mat-icon> </button> <span>Contact Manager</span> </mat-toolbar> |
با توجه به استفادهی از fxHide، یعنی دکمهی نمایش منوی همبرگری در تمام حالات مخفی خواهد بود. برای لغو آن و نمایش آن در حالت موبایل، از حالت واکنشگرای آن یعنی fxHide.xs استفاده میکنیم (قسمت «کار با API واکنشگرای Angular Flex layout» در مطلب قبلی این سری). به این ترتیب زمانیکه کاربر اندازهی صفحه را کوچک میکند و یا اندازهی واقعی صفحهی نمایش او کوچک است، این دکمه نمایان خواهد شد.
همچنین در sidenav یک چنین تعریفی را داریم:
<app-toolbar (toggleSidenav)="sidenav.toggle()"></app-toolbar>
محتویات فایل toolbar\toolbar.component.ts:
import { Component, EventEmitter, OnInit, Output } from "@angular/core"; @Component({ selector: "app-toolbar", templateUrl: "./toolbar.component.html", styleUrls: ["./toolbar.component.css"] }) export class ToolbarComponent implements OnInit { @Output() toggleSidenav = new EventEmitter<void>(); constructor() { } ngOnInit() { } }
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: MaterialAngularClient-02.zip
برای اجرای آن نیز ابتدا فایل restore.bat و سپس فایل ng-serve.bat را اجرا کنید. پس از اجرای برنامه، یکبار آنرا در حالت تمام صفحه و بار دیگر با کوچکتر کردن اندازهی مرورگر آزمایش کنید. در حالتیکه به اندازهی موبایل رسیدید، بر روی دکمهی همبرگری نمایان شده کلیک کنید تا عکس العمل آن و نمایش مجدد sidenav را در حالت over، مشاهده نمائید.