程式碼研究室簡介
1. 簡介
Material Design 元件 (MDC) 可協助開發人員實作質感設計。MDC 是由 Google 工程師和使用者體驗設計師團隊打造,提供數十種精美且功能豐富的 UI 元件,適用於 Android、iOS、網頁和 Flutter.material.io/develop |
MDC Web 經過精心設計,能整合至任何前端架構,同時堅持質感設計原則。以下程式碼研究室會引導您建構 React 元件,以使用 MDC Web 做為基礎。本程式碼研究室介紹的原則可應用於任何 JavaScript 架構。
MDC 網路的建構方式
MDC Web 的 JavaScript 層的每個元件由三個類別組成:元件、基礎和轉接器。此模式讓 MDC Web 靈活地與前端架構整合。
基礎包含實作 Material Design 的商業邏輯。基礎不會參照任何 HTML 元素。以便我們將 HTML 互動邏輯擷取至轉接程式。Foundation 有 Adapter。
轉接器是介面。Foundation 會參照 Adapter 介面,以導入 Material Design 商業邏輯。您可以使用 Angular 或 React 等其他架構實作轉接程式。轉接程式的實作會與 DOM 結構互動。
元件具備基礎,角色則適用於
- 導入轉接程式 (使用非架構 JavaScript),並
- 提供公開方法,以 Proxy 為基礎中的方法。
MDC Web 的功能
MDC Web 的每個套件都隨附 元件、Foundation 和 Adapter。如要將元件例項化,您必須將根「元素」傳遞至元件的建構函式方法。元件會導入轉接程式,與 DOM 和 HTML 元素互動。Component 接著會將 Foundation 執行個體化,進而呼叫 Adapter 方法。
如要將 MDC Web 整合到架構中,您必須以該架構的語言/語法建立自己的元件。架構 元件 會實作 MDC Web 的轉接程式,並使用 MDC Web 的基礎。
建構項目
本程式碼研究室將說明如何建構自訂 Adapter,以使用 Foundation 邏輯,實現 Material Design React 元件。並涵蓋整合至架構一文的進階主題。本程式碼研究室將 React 做為範例架構使用,但此方法也適用於任何其他架構。
在本程式碼研究室中,您將建構頂端應用程式列,並重新建立頂端應用程式列的示範頁面。示範頁面版面配置已設定完成,因此您可以開始使用頂端應用程式列。頂端應用程式列包括:
- 導覽圖示
- 待辦事項
- 目前提供 4 種變化版本:「短」、「一律收合」、「固定」和「顯眼」的變化版本
需求條件:
針對網站開發的經驗程度,你會給予什麼評價?
2. 設定開發環境
下載程式碼研究室入門應用程式
範例應用程式位於 material-components-web-codelabs-master/mdc-112/starter
目錄中。
...或是從 GitHub 複製檔案
如要從 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/,即可查看該網頁。
大功告成!「頂端應用程式列反應示範」頁面的範例程式碼應在瀏覽器中執行。您應該會看到 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
的進入點。
開啟內含 render
方法的裸機 Component
類別 TopAppBar.js
檔案:
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 的說明文件。
將 TopAppBar.js
中的 render()
方法修改為如下所示:
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
元素。您可以在 App.js
中查看初始化 TopAppBar
的程式碼範例。
缺少用於 render
方法的 getMergedStyles
方法。請將下列 JavaScript 方法加入 TopAppBar
類別:
getMergedStyles = () => {
const {style} = this.props;
const {style: internalStyle} = this.state;
return Object.assign({}, internalStyle, style);
}
render
方法中也缺少 this.classes
,但我們會在後續章節中說明。除了缺少的 getter 方法 this.classes
以外,您還需要實作 TopAppBar
部分,頂端應用程式列才能正確顯示。
上方應用程式列中仍缺少的 React 元件部分如下:
- 已初始化的基礎
- 傳遞至基礎的轉接方法
- JSX 標記
- 變化版本管理 (固定、簡短、一律收合、醒目)
方法
- 實作 Adapter 方法。
- 初始化
componentDidMount
中的 Foundation。 - 在
componentWillUnmount
中呼叫 Foundation.destroy 方法。 - 透過結合適當的類別名稱的 getter 方法,建立變數管理。
4. 實作轉接程式方法
非架構 JS TopAppBar
元件會導入下列轉接程式方法 (詳見這裡):
hasClass()
addClass()
removeClass()
registerNavigationIconInteractionHandler()
deregisterNavigationIconInteractionHandler()
notifyNavigationIconClicked()
setStyle()
getTopAppBarHeight()
registerScrollHandler()
deregisterScrollHandler()
registerResizeHandler()
deregisterResizeHandler()
getViewportScrollY()
getTotalActionItems()
由於 React 具有綜合事件,以及不同的最佳做法和模式,因此您必須重新導入 Adapter 方法。
Adapter Getter 方法
在 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
物件上的函式,而不在 React 的 API 中。每個架構的轉接程式導入方式各不相同。
您可能會發現缺少由 get adapter
方法呼叫的 this.setStyle
。在 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
執行的 Adapter 方法。 - 在
<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,「Control」核取方塊現在應切換為開啟/關閉 DOM 的類別名稱。
這段程式碼可讓許多開發人員使用 TopAppBar
。開發人員可以與 TopAppBar
API 互動,無須擔心 CSS 類別的實作細節。
您已成功實作轉接程式。下一節將逐步引導您建立基礎。
掛接和卸載元件
Foundation 會在 componentDidMount
方法中進行例項化。
首先,請在 TopAppBar.js
的現有匯入內容後方新增下列匯入,以匯入 MDC 頂端應用程式列基礎:
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();
}
...
}
定義 propTypes 和 defaultProps 是很好的 React 程式設計做法。在 TopAppBar.js 中現有的匯入之後,新增以下匯入內容:
import PropTypes from 'prop-types';
接著,在 TopAppBar.js
底部 (元件類別之後) 新增以下程式碼:
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 的 Foundation,以便用於 React 應用程式。GitHub 和 npm 中的幾個程式庫會包裝 MDC Web 元件,如整合至架構中所述。建議你使用這裡的清單。除了 React 以外,這份清單也提供其他架構,例如 Angular 和 Vue。
本教學課程將重點說明我們決定將 MDC 網頁程式碼分為 3 個部分:Foundation、Adapter 和元件。此架構讓元件可共用通用程式碼,同時與所有架構搭配使用。感謝您試用 Material Design 元件 React,並瞭解我們新推出的 MDC React 程式庫。希望您喜歡本程式碼研究室!