ایجاد منوی کشویی (side drawer)

22 بهمن 1399
ایجاد منوی کشویی (side drawer)

ایجاد منوی کشویی در ری اکت (side drawer)

در قسمت قبل toolbar را کدنویسی کردیم اما هنوز منوی کشویی در ری اکت را ایجاد نکرده ایم. منوی کشویی معادل responsive نوار toolbar برای گوشی های موبایل است. برای شروع کار در پوشه ی Navigation یک پوشه ی جدید به نام SideDrawer بسازید که حاوی فایلی به نام SideDrawer.js باشد. در ابتدا محتوای SideDawer.js مانند تمام کامپوننت های کاربردی دیگرمان و به شکل زیر است:

import React from 'react';

import Logo from '../../Logo/Logo';
import NavigationItems from '../NavigationItems/NavigationItems';

const sideDrawer = (props) => {
    // ....
    return (

    );
}

export default sideDrawer;

ما می خواهیم در این تابع کلاس های CSS را به صورت پویا تغییر بدهیم تا منوی کشویی وارد صفحه شود یا با بسته شدن آن از صفحه خارج شود؛ فعلا به جای این کدها از یک کامنت با چند نقطه استفاده کرده ایم اما بعدا کدهای آن را تکمیل می کنیم. همچنین از آنجایی که می خواهیم از آیتم های navigation استفاده کنیم، این کامپوننت را import کرده ایم و نیازی به دوباره نویسی کدها نیست.

برای تکمیل کدها می نویسیم:

const sideDrawer = (props) => {
    // ....
    return (
        <div>
            <Logo />
            <nav>
                <NavigationItems />
            </nav>
        </div>
    );
}

یعنی لوگو و آیتم های navigation باید درون این کامپوننت باشند، اما کجا باشند؟ درست است باید آن ها را استایل دهی کنیم بنابراین در کنار فایل SideDrawer.js یک فایل به نام SideDrawer.module.css ایجاد کنید و کلاس ها و استایل های زیر را در آن قرار دهید:

.SideDrawer {
    position: fixed;
    width: 280px;
    max-width: 70%;
    height: 100%;
    left: 0;
    top: 0;
    z-index: 200;
    background-color: white;
    padding: 32px 16px;
    box-sizing: border-box;
    transition: transform 0.3s ease-out;
}

@media (min-width: 500px) {
    .SideDrawer {
        display: none;
    }
}

.Open {
    transform: translateX(0);
}

.Close {
    transform: translateX(-100%);
}

نکات مهم:

  • z-index از عمد بالاتر از مقدار backdrop است تا زیر آن نرود و کاربران بتوانند با آن تعامل داشته باشند.
  • اضافه کردن transition برای ایجاد انیمیشن است.
  • در صفحاتی با عرض بیشتر از 500 پیکسل display را none گذاشته ایم تا منوی کشویی در دستگاه های بزرگ مانند لپتاپ ها دیده نشود.
  • کلاس های open و close به صورت پویا و توسط جاوا اسکریپت به عنصر اضافه یا حذف خواهند شد. کلاس open مقدار translatex صفر دارد یعنی عنصر در جای خودش قرار می گیرد (کلاس اصلی top و left را صفر قرار داده بودیم، یعنی به همانجا برمی گردد). کلاس close نیز عنصر را 100 درصد روی محور x ها جا به جا می کند که قاعدتا از Viewport کاربر خارج خواهد شد.

حالا به فایل SideDrawer.js برگردید تا از این کلاس ها استفاده کنیم. ابتدا باید کلاس ها را import کنیم:

import classes from './SideDrawer.module.css';

سپس آن را به Div ریشه ای اضافه می کنیم:

     return (
        <div className={classes.SideDrawer}>
            <Logo />
            <nav>
                <NavigationItems />
            </nav>
        </div>
    );

در این مرحله باید از خودمان بپرسیم که SideDrawer را کجا قرار دهیم؟ درون App.js یا درون Toolbar یا جایی دیگر؟ اگر یادتان باشد Toolbar را درون Layout.js قرار دادیم و گفتیم که دلیل آن حضور Toolbar در تمامی صفحات سایت است. با همین منطق می توانیم SideDrawer را نیز در Layout.js اضافه کنیم. محتویات فایل Layout.js پس از اضافه کردن SideDrawer:

import React from 'react';
import Aux from '../../hoc/Auxx';
import classes from './Layout.module.css';
import Toolbar from '../Navigation/Toolbar/Toolbar';
import SideDrawer from '../Navigation/SideDrawer/SideDrawer';

const layout = (props) => (
    <Aux>
        <Toolbar />
        <SideDrawer />
        <main className={classes.Content}>
            {props.children}
        </main>
    </Aux>
);

export default layout;

اگر فایل ها را ذخیره کنیم و به مرورگر برویم چیزی مشاهده نمی شود. چرا؟ به دلیل اینکه گفته بودیم در دستگاه هایی با عرض صفحه ی بیشتر از 500 پیکسل SideDrawer نباید نمایش داده شود اما اگر سایز پنجره ی کروم را کوچک کنید و یا دکمه ی پیش نمایش mobile را از dev tools بزنید (قسمت مشخص شده در تصویر زیر)، SideDrawer را مشاهده خواهید کرد:

پیش نمایش منوی کشویی
پیش نمایش منوی کشویی

همانطور که می بینید اصلا ظاهر خوبی ندارد؛ لوگو بسیار بزرگ است و دکمه های navigation نیز پراکنده شده اند. البته جای تعجب هم ندارد چرا که ما هنوز آن ها را برای صفحات کوچک تنظیم نکرده ایم.

اگر یادتان باشد در فایل Logo.module.css مقدار height برای لوگو را 80 درصد قرار داده ایم:

.Logo {
    background-color: white;
    padding: 8px;
    height: 80%;
    box-sizing: border-box;
    border-radius: 5px;
}

به همین دلیل است که لوگو آنقدر بزرگ نمایش داده می شود. برای حل این مشکل راه های مختلفی وجود دارد؛ مثلا می توانیم با استفاده از media query ها یک طراحی Responsive را پیاده سازی کنیم اما اگر چنین کاری را انجام دهیم، استفاده ی دوباره از لوگو سخت تر می شود. هدف ما این بود که بتوانیم بدون کدنویسی اضافه از کامپوننت ها استفاده کنیم اما با طراحی Responsive باید هر بار برای لوگو media query بنویسیم. بنابراین در فایل Logo.module.css مقدار height را روی 100 درصد قرار بدهید:

.Logo {
    background-color: white;
    padding: 8px;
    height: 100%;
    box-sizing: border-box;
    border-radius: 5px;
}

حالا اندازه ی لوگو را درون Toolbar و SideDrawer تغییر می دهیم. ما می توانیم Toolbar.js را باز کرده و مقدار height را به صورت یک prop به فایل خودمان پاس بدهیم:

 const toolbar = (props) => (
    <header className={classes.Toolbar}>
        <div>MENU</div>
        <Logo height="80%" />
        <nav>
            <NavigationItems />
        </nav>
    </header>
);

سپس به Logo.js می رویم و این prop را دریافت کرده و با استفاده از استایل های inline مقدار را تغییر می دهیم:

const logo = (props) => (
    <div className={classes.Logo} style={{ height: props.height }}>
        <img src={burgerLogo} alt="MyBurger" />
    </div>
);

حالا وارد SideDrawer.js شده و همین کار را انجام دهید:

    return (
        <div className={classes.SideDrawer}>
            <Logo height="11%" />
            <nav>
                <NavigationItems />
            </nav>
        </div>
    );

اگر فایل ها را ذخیره کنید و به مرورگر بروید متوجه می شوید که مشکل ما از نظر اندازه ی لوگو حل شده است:

لوگو با سایز مناسب قابل مشاهده است
لوگو با سایز مناسب قابل مشاهده است

البته یک روش دیگر هم وجود دارد که می خواهم آن را به شما نشان بدهم. در روش دوم حل این مشکل به جای پاس دادن اندازه ی height این کار را می کنیم:

    return (
        <div className={classes.SideDrawer}>
            <div>
                <Logo />
            </div>
            <nav>
                <NavigationItems />
            </nav>
        </div>
    );

یعنی لوگو را درون یک div قرار می دهیم. همین کار را برای Toolbar نیز انجام می دهیم:

const toolbar = (props) => (
    <header className={classes.Toolbar}>
        <div>MENU</div>
        <div>
            <Logo />
        </div>
        <nav>
            <NavigationItems />
        </nav>
    </header>
);

سپس به فایل Toolbar.module.css می رویم و کلاسی به نام Logo را به آن اضافه می کنیم:

.Logo {
    height: 80%;
}

همین کار را با SideDrawer.module.css انجام می دهیم:

.Logo {
    height: 11%;
}

حالا وارد فایل SideDrawer.js شده و این کلاس را به div مورد نظر بدهید:

    return (
        <div className={classes.SideDrawer}>
            <div className={classes.Logo}>
                <Logo />
            </div>
            <nav>
                <NavigationItems />
            </nav>
        </div>
    );

اگر فایل ها را ذخیره کرده و به مرورگر بروید با همان نتیجه ی قبلی روبرو می شوید:

لوگو با سایز مناسب قابل مشاهده است
لوگو با سایز مناسب قابل مشاهده است

نکته: شاید فکر کنید که کلاس های Logo با هم تداخل پیدا می کنند اما ما از CSS Module ها استفاده می کنیم؛ یعنی در هنگام ایجاد برنامه نام این کلاس ها تغییر پیدا می کند (مثلا می شود Logo_Logo__3Ndfk) بنابراین هیچ تداخلی پیش نمی آید.

هر دو روش، روش های خوبی هستند و استفاده از آن ها به سلیقه ی شما بستگی دارد. در قسمت بعد آیتم های navigation را سر جایشان قرار خواهیم داد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش ری اکت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.