۱. مقدمه
کامپوننتهای متریال (MDC) به توسعهدهندگان در پیادهسازی طراحی متریال کمک میکنند. MDC که توسط تیمی از مهندسان و طراحان UX در گوگل ایجاد شده است، دهها کامپوننت رابط کاربری زیبا و کاربردی را ارائه میدهد و برای اندروید، iOS، وب و Flutter.material.io/develop در دسترس است. |
MDC Web به گونهای مهندسی شده است که با هر فریمورک front-end سازگار باشد و در عین حال اصول طراحی متریال را رعایت کند. آزمایشگاه کد زیر شما را در ساخت یک کامپوننت React که از MDC Web به عنوان پایه استفاده میکند، راهنمایی میکند. اصول آموخته شده در این آزمایشگاه کد را میتوان در هر فریمورک جاوا اسکریپتی اعمال کرد.
چگونه MDC Web ساخته شده است
لایه جاوا اسکریپت MDC Web از سه کلاس به ازای هر کامپوننت تشکیل شده است: کامپوننت ، فونداسیون و آداپتور . این الگو به MDC Web انعطافپذیری لازم برای ادغام با فریمورکهای frontend را میدهد.
بنیاد شامل منطق تجاری است که طراحی متریال را پیادهسازی میکند. بنیاد به هیچ عنصر HTML ارجاع نمیدهد. این به ما اجازه میدهد منطق تعامل HTML را در Adapter خلاصه کنیم. بنیاد یک Adapter دارد.
آداپتور یک رابط است. رابط آداپتور توسط بنیاد برای پیادهسازی منطق کسبوکار طراحی متریال ارجاع داده شده است. شما میتوانید آداپتور را در چارچوبهای مختلفی مانند Angular یا React پیادهسازی کنید. پیادهسازی یک آداپتور با ساختار DOM تعامل دارد.
این کامپوننت یک پایه دارد و نقش آن این است که
- آداپتور را با استفاده از جاوا اسکریپت غیر فریم ورکی پیادهسازی کنید، و
- متدهای عمومی ارائه دهید که به متدهای موجود در Foundation پروکسی (نمایندگی) میدهند.
آنچه MDC Web ارائه میدهد
هر بسته در MDC Web با یک Component ، Foundation و Adapter ارائه میشود. برای نمونهسازی یک Component، باید عنصر ریشه را به متد سازنده Component ارسال کنید. Component یک Adapter را پیادهسازی میکند که با عناصر DOM و HTML تعامل دارد. سپس Component ، Foundation را نمونهسازی میکند که متدهای Adapter را فراخوانی میکند.
برای ادغام MDC Web در یک چارچوب، باید کامپوننت خودتان را با زبان/نحوهی آن چارچوب ایجاد کنید. کامپوننت چارچوب، Adapter مربوط به MDC Web را پیادهسازی کرده و از Foundation مربوط به MDC Web استفاده میکند.
آنچه خواهید ساخت
این آزمایشگاه کد، نحوه ساخت یک آداپتور سفارشی را برای استفاده از منطق Foundation جهت دستیابی به یک کامپوننت React با طراحی متریال نشان میدهد. این آزمایشگاه، مباحث پیشرفته موجود در بخش «ادغام در فریمورکها» را پوشش میدهد. React در این آزمایشگاه کد به عنوان یک فریمورک نمونه استفاده شده است، اما این رویکرد را میتوان برای هر فریمورک دیگری نیز به کار برد.
در این آزمایشگاه کد، نوار برنامه برتر (Top App Bar) را خواهید ساخت و صفحه نمایشی نوار برنامه برتر (Top App Bar) را بازسازی خواهید کرد. طرحبندی صفحه نمایشی از قبل تنظیم شده است، بنابراین میتوانید کار روی نوار برنامه برتر (Top App Bar) را شروع کنید. نوار برنامه برتر شامل موارد زیر خواهد بود:
- نماد ناوبری
- موارد اقدام
- ۴ نوع مختلف از آن موجود است: کوتاه ، همیشه جمعشده ، ثابت و برجسته
آنچه نیاز دارید:
- نسخه جدیدی از Node.js (که به همراه npm ، یک مدیر بسته جاوا اسکریپت، ارائه میشود)
- کد نمونه (که در مرحله بعد دانلود خواهد شد)
- آشنایی اولیه با HTML، CSS، جاوا اسکریپت و React
سطح تجربه خود در توسعه وب را چگونه ارزیابی میکنید؟
۲. محیط توسعه را تنظیم کنید
اپلیکیشن استارتر codelab را دانلود کنید
برنامهی آغازین در دایرکتوری material-components-web-codelabs-master/mdc-112/starter قرار دارد.
... یا آن را از گیتهاب کلون کنید
برای کپی کردن این codelab از گیتهاب، دستورات زیر را اجرا کنید:
git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-112/starter
نصب وابستگیهای پروژه
از دایرکتوری شروع کننده material-components-web-codelabs/mdc-112/starter ، دستور زیر را اجرا کنید:
npm install
فعالیتهای زیادی را مشاهده خواهید کرد و در پایان، ترمینال شما باید نصب موفقیتآمیز را نشان دهد:

برنامه شروع کننده را اجرا کنید
در همان دایرکتوری، دستور زیر را اجرا کنید:
npm start
webpack-dev-server شروع به کار خواهد کرد. برای مشاهده صفحه، مرورگر خود را به آدرس http://localhost:8080/ هدایت کنید.

موفقیت! کد آغازین برای صفحه دموی React مربوط به Top App Bar باید در مرورگر شما اجرا شود. شما باید دیواری از متن lorem ipsum ، یک کادر Controls (پایین سمت راست) و یک Top App Bar ناتمام را ببینید:

نگاهی به کد و پروژه بیندازید
اگر ویرایشگر کد خود را باز کنید، دایرکتوری پروژه باید چیزی شبیه به این باشد:

فایل App.js را باز کنید و به متد render که شامل کامپوننت <TopAppBar> است، نگاهی بیندازید:
برنامه.js
render() {
const {isFixed, isShort, isRtl, isProminent, isAlwaysCollapsed, shouldReinit} = this.state;
return (
<section
dir={isRtl ? 'rtl' : 'ltr'}
className='mdc-typography'>
{
shouldReinit ? null :
<TopAppBar
navIcon={this.renderNavIcon()}
short={isShort}
prominent={isProminent}
fixed={isFixed}
alwaysCollapsed={isAlwaysCollapsed}
title='Mountain View, CA'
actionItems={this.actionItems}
/>
}
<div className={classnames('mdc-top-app-bar--fixed-adjust', {
'mdc-top-app-bar--short-fixed-adjust': isShort || isAlwaysCollapsed,
'mdc-top-app-bar--prominent-fixed-adjust': isProminent,
})}>
{this.renderDemoParagraphs()}
</div>
{this.renderControls()}
</section>
);
}
این نقطه ورود TopAppBar در برنامه است.
فایل TopAppBar.js را که یک کلاس Component React با یک متد render است، باز کنید:
TopAppBar.js
import React from 'react';
export default class TopAppBar extends React.Component {
render() {
return (
<header>
TOP APP BAR
</header>
);
}
}
۳. ترکیب اجزا
در React، متد render HTML کامپوننت را خروجی میدهد. کامپوننت Top App Bar یک تگ <header /> را رندر میکند و از دو بخش اصلی تشکیل شده است:
- نماد ناوبری و بخش عنوان
- بخش آیکونهای اکشن
اگر در مورد عناصری که نوار برنامه بالا را تشکیل میدهند سؤالی دارید، به مستندات موجود در GitHub مراجعه کنید.
متد render() را در TopAppBar.js به صورت زیر تغییر دهید:
render() {
const {
title,
navIcon,
} = this.props;
return (
<header
className={this.classes}
style={this.getMergedStyles()}
ref={this.topAppBarElement}
>
<div className='mdc-top-app-bar__row'>
<section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-start'>
{navIcon ? navIcon : null}
<span className="mdc-top-app-bar__title">
{title}
</span>
</section>
{this.renderActionItems()}
</div>
</header>
);
}
دو عنصر بخش در این HTML وجود دارد. اولی شامل یک آیکون ناوبری و عنوان است. دومی شامل آیکونهای عملیاتی است.
سپس، متد renderActionItems را اضافه کنید:
renderActionItems() {
const {actionItems} = this.props;
if (!actionItems) {
return;
}
return (
<section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-end' role='toolbar'>
{/* need to clone element to set key */}
{actionItems.map((item, key) => React.cloneElement(item, {key}))}
</section>
);
}
یک توسعهدهنده TopAppBar به برنامه React خود وارد میکند و آیکونهای اکشن را به عنصر TopAppBar ارسال میکند. میتوانید نمونه کد مقداردهی اولیه TopAppBar در App.js مشاهده کنید.
متد getMergedStyles که در متد render استفاده میشود، وجود ندارد. لطفاً متد جاوا اسکریپت زیر را به کلاس TopAppBar اضافه کنید:
getMergedStyles = () => {
const {style} = this.props;
const {style: internalStyle} = this.state;
return Object.assign({}, internalStyle, style);
}
this.classes نیز در متد render وجود ندارد، اما در بخش بعدی به آن پرداخته خواهد شد. علاوه بر فقدان متد getter، this.classes ، هنوز بخشهایی از TopAppBar وجود دارد که باید پیادهسازی کنید تا Top App Bar بتواند به درستی رندر شود.
بخشهایی از کامپوننت React که هنوز در Top App Bar وجود ندارند عبارتند از:
- یک فونداسیون اولیه
- روشهای آداپتور برای عبور به فونداسیون
- نشانهگذاری JSX
- مدیریت متغیر (ثابت، کوتاه، همیشه جمع شده، برجسته)
رویکرد
- متدهای Adapter را پیادهسازی کنید.
- Foundation را در
componentDidMountمقداردهی اولیه کنید. - متد Foundation.destroy را در
componentWillUnmountفراخوانی کنید. - مدیریت متغیرها را از طریق یک متد geter که نامهای کلاس مناسب را ترکیب میکند، برقرار کنید.
۴. پیادهسازی متدهای آداپتور
کامپوننت غیر فریمورکی JS TopAppBar متدهای Adapter زیر را پیادهسازی میکند (که جزئیات آنها در اینجا آمده است):
-
hasClass() -
addClass() -
removeClass() -
registerNavigationIconInteractionHandler() -
deregisterNavigationIconInteractionHandler() -
notifyNavigationIconClicked() -
setStyle() -
getTopAppBarHeight() -
registerScrollHandler() -
deregisterScrollHandler() -
registerResizeHandler() -
deregisterResizeHandler() -
getViewportScrollY() -
getTotalActionItems()
از آنجا که React دارای رویدادهای مصنوعی و بهترین شیوهها و الگوهای کدنویسی متفاوتی است، متدهای Adapter باید دوباره پیادهسازی شوند.
روش گیرنده آداپتور
در فایل TopAppBar.js متد جاوا اسکریپت زیر را به TopAppBar اضافه کنید:
get adapter() {
const {actionItems} = this.props;
return {
hasClass: (className) => this.classes.split(' ').includes(className),
addClass: (className) => this.setState({classList: this.state.classList.add(className)}),
removeClass: (className) => {
const {classList} = this.state;
classList.delete(className);
this.setState({classList});
},
setStyle: this.setStyle,
getTopAppBarHeight: () => this.topAppBarElement.current.clientHeight,
registerScrollHandler: (handler) => window.addEventListener('scroll', handler),
deregisterScrollHandler: (handler) => window.removeEventListener('scroll', handler),
registerResizeHandler: (handler) => window.addEventListener('resize', handler),
deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler),
getViewportScrollY: () => window.pageYOffset,
getTotalActionItems: () => actionItems && actionItems.length,
};
}
APIهای آداپتور برای ثبت رویدادهای اسکرول و تغییر اندازه، دقیقاً مشابه نسخه غیر فریمورکی JS پیادهسازی شدهاند، زیرا React هیچ رویداد مصنوعی برای اسکرول یا تغییر اندازه ندارد و به سیستم رویداد DOM بومی (native DOM) وابسته است. getViewPortScrollY نیز باید به DOM بومی وابسته باشد، زیرا تابعی روی شیء window است که در API React وجود ندارد. پیادهسازیهای آداپتور برای هر فریمورک متفاوت خواهد بود.
ممکن است متوجه شوید که this.setStyle که توسط متد get adapter فراخوانی میشود، وجود ندارد. در فایل TopAppBar.js ، متد جاوا اسکریپتِ از دست رفته را به کلاس TopAppBar اضافه کنید:
setStyle = (varName, value) => {
const updatedStyle = Object.assign({}, this.state.style);
updatedStyle[varName] = value;
this.setState({style: updatedStyle});
}
شما به تازگی Adapter را پیادهسازی کردهاید! توجه داشته باشید که در این مرحله ممکن است خطاهایی در کنسول خود مشاهده کنید زیرا پیادهسازی کامل هنوز کامل نشده است. بخش بعدی شما را در نحوه اضافه کردن و حذف کلاسهای CSS راهنمایی خواهد کرد.
۵. پیادهسازی متدهای کامپوننت
مدیریت متغیرها و کلاسها
React رابط برنامهنویسی کاربردی (API) برای مدیریت کلاسها ندارد. برای تقلید از متدهای کلاس CSS اضافه/حذف جاوااسکریپت بومی، متغیر state classList را اضافه کنید. سه قطعه کد در TopAppBar وجود دارد که با کلاسهای CSS تعامل دارند:
- کامپوننت
<TopAppBar />از طریق propclassName. - متد Adapter از طریق
addClassیاremoveClass. - درون کامپوننت React
<TopAppBar />به صورت هاردکد نوشته شده است.
ابتدا، ایمپورت زیر را در بالای TopAppBar.js و زیر ایمپورتهای موجود اضافه کنید:
import classnames from 'classnames';
سپس کد زیر را داخل تعریف کلاس کامپوننت TopAppBar اضافه کنید:
export default class TopAppBar extends React.Component {
constructor(props) {
super(props);
this.topAppBarElement = React.createRef();
}
state = {
classList: new Set(),
style: {},
};
get classes() {
const {classList} = this.state;
const {
alwaysCollapsed,
className,
short,
fixed,
prominent,
} = this.props;
return classnames('mdc-top-app-bar', Array.from(classList), className, {
'mdc-top-app-bar--fixed': fixed,
'mdc-top-app-bar--short': short,
'mdc-top-app-bar--short-collapsed': alwaysCollapsed,
'mdc-top-app-bar--prominent': prominent,
});
}
...
}
اگر به آدرس http://localhost:8080 بروید، اکنون کادرهای انتخاب Controls باید نام کلاسها را از DOM فعال/غیرفعال کنند.
این کد، TopAppBar را برای بسیاری از توسعهدهندگان قابل استفاده میکند. توسعهدهندگان میتوانند بدون نگرانی در مورد جزئیات پیادهسازی کلاسهای CSS، با API مربوط TopAppBar تعامل داشته باشند.
اکنون شما با موفقیت Adapter را پیادهسازی کردهاید. بخش بعدی شما را در نمونهسازی یک Foundation راهنمایی خواهد کرد.
نصب و جداسازی قطعه
نمونهسازی Foundation در متد componentDidMount انجام میشود.
ابتدا، با اضافه کردن import زیر پس از importهای موجود در TopAppBar.js ، پایههای MDC Top App Bar را import کنید:
import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';
سپس، کد جاوا اسکریپت زیر را به کلاس TopAppBar اضافه کنید:
export default class TopAppBar extends React.Component {
...
foundation_ = null;
componentDidMount() {
this.initializeFoundation();
}
componentWillUnmount() {
this.foundation_.destroy();
}
initializeFoundation = () => {
if (this.props.short) {
this.foundation_ = new MDCShortTopAppBarFoundation(this.adapter);
} else if (this.props.fixed) {
this.foundation_ = new MDCFixedTopAppBarFoundation(this.adapter);
} else {
this.foundation_ = new MDCTopAppBarFoundation(this.adapter);
}
this.foundation_.init();
}
...
}
یک روش خوب برای کدنویسی React، تعریف propTypes و defaultProps است. کد زیر را بعد از importهای موجود در TopAppBar.js اضافه کنید:
import PropTypes from 'prop-types';
سپس کد زیر را به انتهای TopAppBar.js (بعد از کلاس Component) اضافه کنید:
import PropTypes from 'prop-types';
TopAppBar.propTypes = {
alwaysCollapsed: PropTypes.bool,
short: PropTypes.bool,
fixed: PropTypes.bool,
prominent: PropTypes.bool,
title: PropTypes.string,
actionItems: PropTypes.arrayOf(PropTypes.element),
navIcon: PropTypes.element,
};
TopAppBar.defaultProps = {
alwaysCollapsed: false,
short: false,
fixed: false,
prominent: false,
title: '',
actionItems: null,
navIcon: null,
};
اکنون شما با موفقیت کامپوننت React مربوط به Top App Bar را پیادهسازی کردهاید. اگر به آدرس http://localhost:8080 بروید، میتوانید با صفحه آزمایشی کار کنید. صفحه آزمایشی مانند صفحه آزمایشی MDC Web عمل خواهد کرد. صفحه آزمایشی باید به شکل زیر باشد:

۶. جمعبندی
در این آموزش، نحوهی استفاده از Foundation مربوط به MDC Web را برای استفاده در یک برنامهی React بررسی کردیم. چند کتابخانه در Github و npm وجود دارند که کامپوننتهای وب MDC را همانطور که در بخش «ادغام در فریمورکها» توضیح داده شده است، در خود جای میدهند. توصیه میکنیم از فهرست موجود در اینجا استفاده کنید. این فهرست علاوه بر React، شامل فریمورکهای دیگری مانند Angular و Vue نیز میشود.
این آموزش، تصمیم ما برای تقسیم کد وب MDC به سه بخش Foundation ، Adapter و Component را برجسته میکند. این معماری به کامپوننتها اجازه میدهد تا در حین کار با همه فریمورکها، کد مشترک را به اشتراک بگذارند. از اینکه Material Components React را امتحان کردید متشکریم و لطفاً کتابخانه جدید ما MDC React را بررسی کنید. امیدواریم از این آزمایشگاه کد لذت برده باشید!