اضافه کردن backdrop به منوی کشویی

22 بهمن 1399
اضافه کردن backdrop به منوی کشویی

اضافه کردن backdrop به منوی کشویی

در قسمت قبل منوی کشویی خود را به صورت واکنش گرا (responsive) درآوردیم و حالا باید backdrop را به آن اضافه کنیم تا بتوانیم با کلیک روی آن، منو را ببندیم. برای انجام این کار ابتدا باید وارد SideDrawer.js شده و کامپوننت backdrop خودمان را import کنیم:

import Backdrop from '../../UI/Backdrop/Backdrop';

در حال حاضر کدهای قسمت JSX بدین شکل هستند:

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

ما نمی توانیم backdrop را درون div ریشه ای قرار بدهیم چرا که این div دربرگیرنده ی منوی کشویی است و اگر backdrop در آن قرار بگیرد، فقط درون منوی کشویی نمایش داده می شود! از طرفی در JSX نمی توانیم دو عنصر ریشه ای داشته باشیم، بنابراین نمی توانیم backdrop را مستقیما خارج از div ریشه ای قرار بدهیم. برای حل این مشکل از کامپوننت Aux استفاده می کنیم که برای همین هدف ساخته شده است. ابتدا آن را import کرده و سپس از آن به عنوان عنصر ریشه ای استفاده می کنیم:

import Backdrop from '../../UI/Backdrop/Backdrop';
import Aux from '../../../hoc/Auxx';

const sideDrawer = (props) => {
    // ....
    return (
        <Aux>
            <Backdrop />
            <div className={classes.SideDrawer}>
                <div className={classes.Logo}>
                    <Logo />
                </div>
                <nav>
                    <NavigationItems />
                </nav>
            </div>
        </Aux>
    );
}

اگر به مرورگر بروید متوجه می شوید که backdrop قابل مشاهده نیست. به نظر شما دلیل آن چیست؟

اگر یادتان باشد، کامپوننت backdrop خصوصیتی به نام show دارد:

const backdrop = (props) => (
    props.show ? <div className={classes.Backdrop} onClick={props.clicked}></div> : null
);

بنابراین می توانیم به صورت دستی مقدار show را به آن پاس بدهیم:

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

یادتان باشد که show یک مقدار Boolean است بنابراین نیازی نیست حتما مقدار true را به آن بدهیم، همین که وجود دارد یعنی true! قدم بعدی این است که backdrop را طوری تنظیم کنیم که با کلیک روی دکمه ی Menu باز شده و با بسته شدن منوی کشویی نیز بسته شود. در واقع SideDrawer از یک طرف با Toolbar کار می کند (دکمه ی Menu) و از طرفی نیز با backdrop و به همین دلیل بهتر است کامپوننتی را پیدا کنیم که Toolbar و SideDrawer هر دو در آن حضور داشته باشند. بله Layout! ما باید Layout.js را تبدیل به یک کامپوننت کلاس-محور کنیم:

import React, { Component } from 'react';

class Layout extends Component {

    render() {
        return (
            <Aux>
                <Toolbar />
                <SideDrawer />
                <main className={classes.Content}>
                    {this.props.children}
                </main>
            </Aux>
        );
    }
}

export default Layout;

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

    sideDrawerClosedHandler = () => {
        
    }

قبل از اینکه بخواهیم کدهای درون این متد را بنویسیم به state نیاز داریم که قرار است حاوی اطلاعاتی باشد که نشان دهد sideDrawer یا همان منوی کشویی باز شده است یا خیر. بنابراین:

    state = {
        showSideDrawer: true
    }

فعلا برای تست کردن کدها و نمایش داده شدنشان، مقدار پیش فرض را روی true قرار میدهیم. حالا می توانیم متدمان را کدنویسی کنیم:

    sideDrawerClosedHandler = () => {
        this.setState({ showSideDrawer: false });
    }

یعنی هر گاه روی backdrop کلیک شد، منوی کشویی بسته شود. بنابراین باید این متد را به SideDrawer پاس بدهیم:

        return (
            <Aux>
                <Toolbar />
                <SideDrawer closed={this.sideDrawerClosedHandler} />
                <main className={classes.Content}>
                    {this.props.children}
                </main>
            </Aux>
        );

مثل همیشه من نام این prop را closed انتخاب کرده ام اما شما می توانید هر نامی دیگری را بر اساس سلیقه ی خود انتخاب کنید. هنوز یک کار دیگر باقی مانده است؛ ما باید مقدار show در SideDrawer را نیز بر اساس state تنظیم کنیم بنابراین یک prop دیگر را نیز به نام دلخواه اضافه نمایید:

<SideDrawer open={this.state.showSideDrawer} closed={this.sideDrawerClosedHandler} />

 حالا به SideDrawer.js بروید و این prop ها را پاس بدهید:

    return (
        <Aux>
            <Backdrop show={props.open} clicked={props.closed} />
            <div className={classes.SideDrawer}>
                <div className={classes.Logo}>
                    <Logo />
                </div>
                <nav>
                    <NavigationItems />
                </nav>
            </div>
        </Aux>
    );

توجه داشته باشید که ما هر دو prop را به backdrop پاس داده ایم. حالا فایل هایتان را ذخیره کنید و به مرورگر بروید. چه می بینید؟ بله مشکل جدیدی داریم! زمانی که روی backdrop کلیک می کنیم، backdrop حذف می شود اما هیچ کدی برای بسته شدن منوی کشویی ننوشته ایم بنابراین منوی کشویی همچنان در محل خود باقی میماند! به نظر شما برای بسته شدن منوی کشویی چه کار باید بکنیم؟

اگر یادتان باشد درون فایل SideDrawer.module.css دو کلاس به نام های close و open تعریف کرده بودیم:

.Open {
    transform: translateX(0);
}

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

ما باید این دو کلاس را به صورت مشروط (بر اساس یک شرط خاص) روی منوی کشویی اعمال کنیم. همانطور که گفتیم این دو کلاس منوی کشویی را از دید کاربر خارج و یا آن را وارد viewport میکنند. همچنین از آنجایی که در SideDrawer.module.css از خصوصیت transition استفاده کرده ایم، منوی کشویی به حالت انیمیشن از کادر خارج خواهد شد.

برای انجام این کار وارد SideDrawer.js شوید و بیرون از قسمت JSX مانند من یک متغیر ایجاد کنید:

 let attachedClasses = [classes.SideDrawer, classes.Close];

 حالا در یک شرط if می گوییم:

    if (props.open) {
        attachedClasses = [classes.SideDrawer, classes.Open];
    }

بنابراین در قسمت JSX باید attachedClasses را به div اصلی پاس بدهیم:

<div className={attachedClasses.join(' ')}>

 نمایی کلی از کدهای SideDrawer.js را در این قسمت مشاهده می کنید:

import React from 'react';

import Logo from '../../Logo/Logo';
import NavigationItems from '../NavigationItems/NavigationItems';
import classes from './SideDrawer.module.css';
import Backdrop from '../../UI/Backdrop/Backdrop';
import Aux from '../../../hoc/Auxx';

const sideDrawer = (props) => {

    let attachedClasses = [classes.SideDrawer, classes.Close];
    if (props.open) {
        attachedClasses = [classes.SideDrawer, classes.Open];
    }

    return (
        <Aux>
            <Backdrop show={props.open} clicked={props.closed} />
            <div className={attachedClasses.join(' ')}>
                <div className={classes.Logo}>
                    <Logo />
                </div>
                <nav>
                    <NavigationItems />
                </nav>
            </div>
        </Aux>
    );
}

export default sideDrawer;

قدم بعدی اضافه کردن دکمه ی Menu است تا با کلیک روی آن منوی کشویی باز شود. این کار را در سمت بعد انجام خواهیم داد.

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

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