1. บทนำ
Material Components (MDC) ช่วยให้นักพัฒนาแอปใช้งาน Material Design ได้ MDC สร้างขึ้นโดยทีมวิศวกรและนักออกแบบ UX ของ Google โดยมีคอมโพเนนต์ UI ที่สวยงามและใช้งานได้หลายสิบรายการ และพร้อมใช้งานสำหรับ Android, iOS, เว็บ และ Flutter.material.io/develop |
MDC Web ได้รับการออกแบบมาเพื่อผสานรวมกับเฟรมเวิร์กฟรอนท์เอนด์ใดก็ได้ในขณะที่ยังคงยึดมั่นในหลักการของ Material Design Codelab ต่อไปนี้จะแนะนำวิธีสร้างคอมโพเนนต์ React ซึ่งใช้ MDC Web เป็นพื้นฐาน คุณสามารถนำหลักการที่ได้เรียนรู้ใน Codelab นี้ไปใช้กับเฟรมเวิร์ก JavaScript ใดก็ได้
วิธีสร้าง MDC Web
เลเยอร์ JavaScript ของ MDC Web ประกอบด้วย 3 คลาสต่อคอมโพเนนต์ ได้แก่ Component, Foundation และ Adapter รูปแบบนี้ช่วยให้ MDC Web มีความยืดหยุ่นในการผสานรวมกับเฟรมเวิร์กส่วนหน้า
Foundation มีตรรกะทางธุรกิจที่ใช้ Material Design Foundation ไม่ได้อ้างอิงองค์ประกอบ HTML ใดๆ ซึ่งช่วยให้เราแยกตรรกะการโต้ตอบ HTML ออกเป็นอแดปเตอร์ได้ Foundation มี Adapter
อแดปเตอร์เป็นอินเทอร์เฟซ Foundation อ้างอิงอินเทอร์เฟซ Adapter เพื่อใช้ตรรกะทางธุรกิจของ Material Design คุณสามารถใช้อแดปเตอร์ในเฟรมเวิร์กต่างๆ เช่น Angular หรือ React การติดตั้งใช้งานของ Adapter จะโต้ตอบกับโครงสร้าง DOM
คอมโพเนนต์มีพื้นฐาน และมีบทบาทในการ
- ติดตั้งใช้งานอแดปเตอร์โดยใช้ JavaScript ที่ไม่ใช่เฟรมเวิร์ก และ
- ระบุเมธอดสาธารณะที่พร็อกซีไปยังเมธอดใน Foundation
สิ่งที่ MDC Web มีให้
ทุกแพ็กเกจใน MDC Web มาพร้อมกับคอมโพเนนต์ Foundation และอแดปเตอร์ หากต้องการสร้างอินสแตนซ์ คอมโพเนนต์ คุณต้องส่งองค์ประกอบรูทไปยังเมธอดเครื่องมือสร้างของคอมโพเนนต์ Component จะใช้ Adapter ซึ่งโต้ตอบกับ DOM และองค์ประกอบ HTML จากนั้นคอมโพเนนต์จะสร้างอินสแตนซ์ของ Foundation ซึ่งจะเรียกใช้เมธอด Adapter
หากต้องการผสานรวม MDC Web เข้ากับเฟรมเวิร์ก คุณต้องสร้างคอมโพเนนต์ของคุณเองในภาษา/ไวยากรณ์ของเฟรมเวิร์กนั้น เฟรมเวิร์ก Component จะใช้ Adapter ของ MDC Web และใช้ Foundation ของ MDC Web
สิ่งที่คุณจะสร้าง
Codelab นี้แสดงวิธีสร้าง Adapter ที่กำหนดเองเพื่อใช้ตรรกะ Foundation เพื่อสร้างคอมโพเนนต์ React ของ Material Design โดยจะครอบคลุมหัวข้อขั้นสูงที่อยู่ในส่วนการผสานรวมกับเฟรมเวิร์ก เราใช้ React ใน Codelab นี้เป็นเฟรมเวิร์กตัวอย่าง แต่คุณสามารถใช้แนวทางนี้กับเฟรมเวิร์กอื่นๆ ได้
ใน Codelab นี้ คุณจะได้สร้างแถบแอปด้านบนและสร้างหน้าตัวอย่างแถบแอปด้านบนขึ้นมาใหม่ เราได้ตั้งค่าเลย์เอาต์หน้าเดโมไว้แล้วเพื่อให้คุณเริ่มทำงานกับแถบแอปด้านบนได้ แถบแอปด้านบนจะมีข้อมูลต่อไปนี้
- ไอคอนการนำทาง
- Action items
- มีตัวเลือก 4 แบบ ได้แก่ Short, always collapsed, fixed และ prominent
สิ่งที่คุณต้องมี
- 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/ เพื่อดูหน้าเว็บ

สำเร็จ! โค้ดเริ่มต้นสำหรับหน้าการสาธิต React ของแถบแอปด้านบนควรทํางานในเบราว์เซอร์ คุณควรเห็นข้อความ lorem ipsum, กล่องการควบคุม (ด้านขวาล่าง) และแถบแอปด้านบนที่ยังไม่เสร็จ

ดูโค้ดและโปรเจ็กต์
หากเปิดตัวแก้ไขโค้ด ไดเรกทอรีโปรเจ็กต์ควรมีลักษณะดังนี้

เปิดไฟล์ 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 เปล่าๆ ที่มีเมธอด 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 ของคอมโพเนนต์ คอมโพเนนต์แถบแอปด้านบนจะแสดงแท็ก <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>
);
}
HTML นี้มีองค์ประกอบส่วน 2 รายการ ส่วนแรกมีไอคอนการนำทางและชื่อ ส่วนที่ 2 มีไอคอนการดำเนินการ
จากนั้นเพิ่มเมธอด 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 โปรดเพิ่มเมธอด 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 ที่ยังขาดหายไปจากแถบแอปด้านบนมีดังนี้
- มูลนิธิที่เริ่มต้นแล้ว
- วิธีการของอะแดปเตอร์ในการส่งไปยังรากฐาน
- มาร์กอัป JSX
- การจัดการรูปแบบ (คงที่ สั้น ยุบอยู่เสมอ โดดเด่น)
วิธีการ
- ใช้เมธอด Adapter
- เริ่มต้น Foundation ใน
componentDidMount - เรียกใช้เมธอด Foundation.destroy ใน
componentWillUnmount - สร้างการจัดการตัวแปรผ่านเมธอด Getter ที่รวมชื่อคลาสที่เหมาะสม
4. ใช้เมธอดของอแดปเตอร์
JS ที่ไม่ใช่เฟรมเวิร์ก TopAppBar Component จะใช้เมธอด Adapter ต่อไปนี้ (แสดงรายละเอียดที่นี่)
hasClass()addClass()removeClass()registerNavigationIconInteractionHandler()deregisterNavigationIconInteractionHandler()notifyNavigationIconClicked()setStyle()getTopAppBarHeight()registerScrollHandler()deregisterScrollHandler()registerResizeHandler()deregisterResizeHandler()getViewportScrollY()getTotalActionItems()
เนื่องจาก React มีเหตุการณ์สังเคราะห์ รวมถึงแนวทางปฏิบัติและรูปแบบการเขียนโค้ดที่ดีที่สุดที่แตกต่างกัน จึงต้องนำวิธีการของ Adapter ไปใช้ใหม่
Adapter Getter Method
ในไฟล์ 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 เวอร์ชันที่ไม่ใช่เฟรมเวิร์ก เนื่องจาก 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});
}
คุณเพิ่งติดตั้งใช้งาน Adapter โปรดทราบว่าคุณอาจเห็นข้อผิดพลาดในคอนโซล ณ จุดนี้เนื่องจากยังไม่ได้ติดตั้งใช้งานอย่างเต็มรูปแบบ ส่วนถัดไปจะแนะนำวิธีเพิ่มและนำคลาส CSS ออก
5. ใช้เมธอดของคอมโพเนนต์
การจัดการรูปแบบและคลาส
React ไม่มี API สำหรับจัดการคลาส หากต้องการเลียนแบบเมธอดการเพิ่ม/นำคลาส CSS ออกของ JavaScript ดั้งเดิม ให้เพิ่มตัวแปรสถานะ classList มีโค้ด 3 ส่วนใน TopAppBar ที่โต้ตอบกับคลาส CSS ดังนี้
<TopAppBar />คอมโพเนนต์ ผ่านพร็อพเพอร์ตี้className- วิธีอะแดปเตอร์ผ่าน
addClassหรือremoveClass - ฮาร์ดโค้ดภายในคอมโพเนนต์
<TopAppBar />React
ก่อนอื่น ให้เพิ่มการนำเข้าต่อไปนี้ที่ด้านบนของ 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 ช่องทำเครื่องหมาย "ตัวควบคุม" ควรเปิด/ปิดชื่อคลาสจาก DOM ได้แล้ว
โค้ดนี้ทำให้ TopAppBar ใช้งานได้โดยนักพัฒนาแอปจำนวนมาก นักพัฒนาแอปสามารถโต้ตอบกับ TopAppBar API ได้โดยไม่ต้องกังวลเกี่ยวกับรายละเอียดการใช้งานของคลาส CSS
ตอนนี้คุณได้ติดตั้งใช้งาน Adapter เรียบร้อยแล้ว ส่วนถัดไปจะแนะนำวิธีสร้างอินสแตนซ์ของ 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. สรุป
ในบทแนะนำนี้ เราได้อธิบายวิธีรวม Foundation ของ MDC Web เพื่อใช้ในแอปพลิเคชัน React มีไลบรารี 2-3 รายการใน Github และ npm ที่ห่อหุ้มคอมโพเนนต์ MDC Web ตามที่อธิบายไว้ในการผสานรวมกับเฟรมเวิร์ก เราขอแนะนำให้คุณใช้รายการที่ระบุไว้ที่นี่ รายการนี้ยังมีเฟรมเวิร์กอื่นๆ นอกเหนือจาก React เช่น Angular และ Vue ด้วย
บทแนะนำนี้จะเน้นย้ำถึงการตัดสินใจของเราในการแยกโค้ด MDC Web ออกเป็น 3 ส่วน ได้แก่ Foundation, Adapter และ Component สถาปัตยกรรมนี้ช่วยให้คอมโพเนนต์แชร์โค้ดทั่วไปได้ในขณะที่ทำงานกับเฟรมเวิร์กทั้งหมด ขอขอบคุณที่ลองใช้ Material Components React และโปรดดูไลบรารีใหม่ของเรา MDC React เราหวังว่าคุณจะชอบ Codelab นี้