1. מבוא
רכיבי Material (MDC) עוזרים למפתחים להטמיע את Material Design. MDC נוצרה על ידי צוות של מהנדסים ומעצבי UX ב-Google. היא כוללת עשרות רכיבי ממשק משתמש יפים ופונקציונליים, וזמינה ל-Android, ל-iOS, לאינטרנט ול-Flutter.material.io/develop |
MDC Web מתוכנן להשתלב בכל מסגרת של ממשק קצה, תוך שמירה על העקרונות של Material Design. ב-Codelab הבא מוסבר איך ליצור רכיב React, שמבוסס על MDC Web. אפשר ליישם את העקרונות שנלמדו ב-codelab הזה בכל מסגרת JavaScript.
איך בנוי MDC Web
שכבת ה-JavaScript של MDC Web מורכבת משלוש מחלקות לכל רכיב: Component, Foundation ו-Adapter. התבנית הזו מאפשרת ל-MDC Web להשתלב עם מסגרות קצה קדמי.
השכבה Foundation מכילה את הלוגיקה העסקית שמיישמת את Material Design. ה-Foundation לא מפנה לרכיבי HTML. כך אנחנו יכולים להפריד את לוגיקת האינטראקציה של HTML אל המתאם. ל-Foundation יש מתאם.
Adapter הוא ממשק. ממשק המתאם מפנה אל Foundation כדי להטמיע את הלוגיקה העסקית של Material Design. אפשר להטמיע את המתאם במסגרות שונות כמו Angular או React. הטמעה של מתאם יוצרת אינטראקציה עם מבנה ה-DOM.
ל-Component יש Foundation, והתפקיד שלו הוא
- מטמיעים את המתאם באמצעות JavaScript שאינו מבוסס על framework, ו
- מספקים methods ציבוריות שפועלות כפרוקסי ל-methods ב-Foundation.
מה אפשר לעשות עם MDC Web
כל חבילה ב-MDC Web כוללת רכיב, שכבת בסיס ומתאם. כדי ליצור מופע של Component, צריך להעביר את element הבסיסי לשיטת הבנאי של Component. הרכיב מטמיע מתאם, שמקיים אינטראקציה עם רכיבי ה-DOM וה-HTML. לאחר מכן, Component יוצר מופע של Foundation, שקורא לשיטות של Adapter.
כדי לשלב את MDC Web במסגרת, צריך ליצור רכיב משלכם בשפה או בתחביר של המסגרת. המסגרת Component מטמיעה את Adapter של MDC Web ומשתמשת ב-Foundation של MDC Web.
מה תפַתחו
ב-Codelab הזה נדגים איך ליצור מתאם בהתאמה אישית כדי להשתמש בלוגיקה של Foundation וליצור רכיב Material Design React. הוא כולל את הנושאים המתקדמים שמופיעים במאמר שילוב עם מסגרות. ב-codelab הזה נעשה שימוש ב-React כדוגמה למסגרת, אבל אפשר להשתמש בגישה הזו בכל מסגרת אחרת.
ב-Codelab הזה תלמדו איך ליצור את סרגל האפליקציות העליון ולשחזר את דף ההדגמה של סרגל האפליקציות העליון. פריסת הדף של ההדגמה כבר מוגדרת, כך שאפשר להתחיל לעבוד על סרגל האפליקציה העליון. הסרגל העליון של האפליקציה יכלול:
- סמל הניווט
- פעולות לביצוע
- יש 4 גרסאות זמינות: קצרה, תמיד מכווצת, קבועה ובולטת
מה צריך:
- גרסה עדכנית של Node.js (שמגיעה עם npm, כלי לניהול חבילות JavaScript)
- קוד לדוגמה (להורדה בשלב הבא)
- ידע בסיסי ב-HTML, CSS, JavaScript ו-React
מה רמת הניסיון שלך בפיתוח אתרים?
2. הגדרת סביבת פיתוח
הורדת האפליקציה לתחילת הדרך של Codelab
אפליקציה לתחילת הדרך נמצאת בספרייה material-components-web-codelabs-master/mdc-112/starter.
...או לשכפל אותו מ-GitHub
כדי לשכפל את ה-codelab הזה מ-GitHub, מריצים את הפקודות הבאות:
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/.

הצלחת! קוד לתחילת הדרך של דף ההדגמה של Top App Bar React צריך לפעול בדפדפן. אמור להופיע קיר של טקסט lorem ipsum, תיבה של Controls (בפינה השמאלית התחתונה) וסרגל אפליקציות עליון לא גמור:

בדיקת הקוד והפרויקט
אם פותחים את עורך הקוד, ספריית הפרויקט אמורה להיראות בערך כך:

פותחים את הקובץ App.js ומסתכלים על השיטה render, שכוללת את הרכיב <TopAppBar>:
App.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 שהוא מחלקה ריקה של React Component עם method render:
TopAppBar.js
import React from 'react';
export default class TopAppBar extends React.Component {
render() {
return (
<header>
TOP APP BAR
</header>
);
}
}
3. הרכב הרכיב
ב-React, הפונקציה render מחזירה את ה-HTML של הרכיב. רכיב Top App Bar יציג תג <header />, והוא יורכב מ-2 חלקים עיקריים:
- סמל הניווט וכותרת הקטע
- הקטע 'סמלי פעולות'
אם יש לכם שאלות לגבי הרכיבים שמרכיבים את סרגל האפליקציות העליון, אתם יכולים לעיין במסמכי התיעוד ב-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>
);
}
יש שני רכיבי section בקוד ה-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. צריך להוסיף את ה-method הבא של JavaScript למחלקה TopAppBar:
getMergedStyles = () => {
const {style} = this.props;
const {style: internalStyle} = this.state;
return Object.assign({}, internalStyle, style);
}
הפרמטר this.classes חסר גם בשיטה render, אבל נסביר עליו בקטע בהמשך. בנוסף לשיטת ה-getter החסרה, this.classes, יש עדיין חלקים של TopAppBar שצריך להטמיע לפני שסרגל האפליקציות העליון יוצג בצורה תקינה.
הרכיבים של React Component שעדיין חסרים ב-Top App Bar הם:
- מודל בסיס מאותחל
- שיטות של מתאמים להעברה למודל הבסיסי
- תגי עיצוב בפורמט JSX
- ניהול וריאנטים (קבוע, קצר, תמיד מכווץ, בולט)
הגישה
- מטמיעים את ה-methods של Adapter.
- מאתחלים את הבסיס ב-
componentDidMount. - מבצעים קריאה ל-method Foundation.destroy ב-
componentWillUnmount. - מגדירים ניהול של וריאציות באמצעות שיטת getter שמשלבת שמות מתאימים של מחלקות.
4. הטמעה של שיטות Adapter
רכיב ה-JS TopAppBar Component שאינו מבוסס על framework מיישם את השיטות הבאות של Adapter (פירוט מלא זמין כאן):
hasClass()addClass()removeClass()registerNavigationIconInteractionHandler()deregisterNavigationIconInteractionHandler()notifyNavigationIconClicked()setStyle()getTopAppBarHeight()registerScrollHandler()deregisterScrollHandler()registerResizeHandler()deregisterResizeHandler()getViewportScrollY()getTotalActionItems()
מכיוון שב-React יש אירועים סינתטיים ושיטות מומלצות ודפוסים שונים של קידוד, צריך להטמיע מחדש את השיטות של המתאם.
שיטת אחזור נתונים של מתאם
בקובץ TopAppBar.js מוסיפים את שיטת ה-JavaScript הבאה ל-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 שאינה מבוססת על framework, כי ל-React אין אירוע סינתטי לגלילה או לשינוי גודל, והיא מסתמכת על מערכת האירועים המקורית של DOM. getViewPortScrollY צריכה גם להסתמך על ה-DOM המקורי כי היא פונקציה באובייקט window, שלא נמצא ב-API של React. ההטמעות של המתאמים יהיו שונות בכל מסגרת.
יכול להיות שתשימו לב שהפונקציה this.setStyle חסרה. הפונקציה הזו נקראת על ידי השיטה get adapter. בקובץ TopAppBar.js, מוסיפים את שיטת ה-JavaScript החסרה למחלקה TopAppBar:
setStyle = (varName, value) => {
const updatedStyle = Object.assign({}, this.state.style);
updatedStyle[varName] = value;
this.setState({style: updatedStyle});
}
הרגע הטמעתם את המתאם! שימו לב: בשלב הזה יכול להיות שיופיעו שגיאות במסוף כי ההטמעה המלאה עדיין לא הושלמה. בקטע הבא מוסבר איך להוסיף ולהסיר מחלקות CSS.
5. הטמעה של שיטות רכיבים
ניהול וריאציות וסוגים
ל-React אין API לניהול כיתות. כדי לחקות את השיטות של JavaScript מקורי להוספה או להסרה של מחלקות CSS, מוסיפים את משתנה המצב classList. יש שלושה קטעי קוד ב-TopAppBar שפועלים עם מחלקות CSS:
<TopAppBar />רכיב באמצעות המאפייןclassName.- שיטת המתאם דרך
addClassאוremoveClass. - מוטמע בקוד בתוך רכיב React
<TopAppBar />.
קודם כול, מוסיפים את הייבוא הבא בחלק העליון של TopAppBar.js, מתחת לייבוא הקיים:
import classnames from 'classnames';
לאחר מכן מוסיפים את הקוד הבא בתוך הצהרת המחלקה של TopAppBar Component:
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, תיבות הסימון של אמצעי הבקרה אמורות להפעיל או להשבית את שמות המחלקות מ-DOM.
הקוד הזה מאפשר למפתחים רבים להשתמש ב-TopAppBar. מפתחים יכולים ליצור אינטראקציה עם TopAppBar API בלי לדאוג לפרטי ההטמעה של מחלקות CSS.
הטמעת המתאם הושלמה. בקטע הבא מוסבר איך ליצור מופע של Foundation.
טעינה וניתוק של הרכיב
ההפעלה של Foundation מתבצעת במתודה componentDidMount.
קודם מייבאים את הבסיס של סרגל האפליקציות העליון של MDC על ידי הוספת הייבוא הבא אחרי הייבוא הקיים ב-TopAppBar.js:
import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';
לאחר מכן, מוסיפים את קוד ה-JavaScript הבא לכיתה 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. מוסיפים את הייבוא הבא אחרי הייבוא הקיים בקובץ 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 של סרגל האפליקציות העליון. אם עוברים אל http://localhost:8080 אפשר להתנסות בדף ההדגמה. דף ההדגמה יפעל כמו דף ההדגמה של MDC Web. דף ההדגמה אמור להיראות כך:

6. סיכום
במדריך הזה הסברנו איך לעטוף את הבסיס של MDC Web כדי להשתמש בו באפליקציית React. יש כמה ספריות ב-Github וב-npm שעוטפות רכיבי MDC Web, כמו שמתואר במאמר בנושא שילוב עם Frameworks. מומלץ להשתמש ברשימה שמופיעה כאן. הרשימה הזו כוללת גם מסגרות אחרות מלבד React, כמו Angular ו-Vue.
במדריך הזה נסביר למה החלטנו לפצל את הקוד של MDC Web ל-3 חלקים: Foundation, Adapter ו-Component. הארכיטקטורה הזו מאפשרת לרכיבים לשתף קוד משותף תוך כדי עבודה עם כל המסגרות. תודה שניסית את Material Components React. כדאי לך לעיין בספרייה החדשה שלנו MDC React. אנחנו מקווים שנהניתם מה-Codelab הזה.