MDC-112 網路:整合 MDC 與 Web 架構

MDC-112 網路:整合 MDC 與 Web 架構

程式碼研究室簡介

subject上次更新時間:10月 11, 2020
account_circle作者:Liz Mitchell, Abhinay Omkar

1. 簡介

logo_components_color_2x_web_96dp.png

Material Design 元件 (MDC) 可協助開發人員實作質感設計。MDC 是由 Google 工程師和使用者體驗設計師團隊打造,提供數十種精美且功能豐富的 UI 元件,適用於 Android、iOS、網頁和 Flutter.material.io/develop

MDC Web 經過精心設計,能整合至任何前端架構,同時堅持質感設計原則。以下程式碼研究室會引導您建構 React 元件,以使用 MDC Web 做為基礎。本程式碼研究室介紹的原則可應用於任何 JavaScript 架構。

MDC Web 的 JavaScript 層的每個元件由三個類別組成:元件基礎轉接器。此模式讓 MDC Web 靈活地與前端架構整合。

基礎包含實作 Material Design 的商業邏輯。基礎不會參照任何 HTML 元素。以便我們將 HTML 互動邏輯擷取至轉接程式FoundationAdapter

轉接器是介面。Foundation 會參照 Adapter 介面,以導入 Material Design 商業邏輯。您可以使用 Angular 或 React 等其他架構實作轉接程式。轉接程式的實作會與 DOM 結構互動。

元件具備基礎,角色則適用於

  1. 導入轉接程式 (使用非架構 JavaScript),並
  2. 提供公開方法,以 Proxy 為基礎中的方法。

MDC Web 的功能

MDC Web 的每個套件都隨附 元件FoundationAdapter。如要將元件例項化,您必須將根「元素」傳遞至元件的建構函式方法。元件會導入轉接程式,與 DOM 和 HTML 元素互動。Component 接著會將 Foundation 執行個體化,進而呼叫 Adapter 方法。

如要將 MDC Web 整合到架構中,您必須以該架構的語言/語法建立自己的元件。架構 元件 會實作 MDC Web 的轉接程式,並使用 MDC Web 的基礎

建構項目

本程式碼研究室將說明如何建構自訂 Adapter,以使用 Foundation 邏輯,實現 Material Design React 元件。並涵蓋整合至架構一文的進階主題。本程式碼研究室將 React 做為範例架構使用,但此方法也適用於任何其他架構。

在本程式碼研究室中,您將建構頂端應用程式列,並重新建立頂端應用程式列的示範頁面。示範頁面版面配置已設定完成,因此您可以開始使用頂端應用程式列。頂端應用程式列包括:

  • 導覽圖示
  • 待辦事項
  • 目前提供 4 種變化版本:「短」、「一律收合」、「固定」和「顯眼」的變化版本

需求條件:

  • 新版 Node.js (JavaScript 套件管理員 npm 隨附)
  • 程式碼範例 (將在下一個步驟中下載)
  • 具備 HTML、CSS、JavaScript 和 React 的基本知識

針對網站開發的經驗程度,你會給予什麼評價?

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

您會看到許多活動,最後的終端機應該會顯示安裝成功:

22a33efc2a687408.png

執行範例應用程式

在同一個目錄中執行:

npm start

webpack-dev-server 將會啟動。將瀏覽器指向 http://localhost:8080/,即可查看該網頁。

b55c66dd400cf34f.png

大功告成!「頂端應用程式列反應示範」頁面的範例程式碼應在瀏覽器中執行。您應該會看到 lorem ipsum 文字、一個「Controls」方塊 (右下方),以及未完成的頂端應用程式列:

4ca3cf6d216f9290.png

查看程式碼和專案

如果您開啟程式碼編輯器,專案目錄看起來會像這樣:

e9a3270d6a67c589.png

開啟 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 個主要部分組成:

  1. 導覽圖示和標題區段
  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 標記
  • 變化版本管理 (固定、簡短、一律收合、醒目)

方法

  1. 實作 Adapter 方法。
  2. 初始化 componentDidMount 中的 Foundation
  3. componentWillUnmount 中呼叫 Foundation.destroy 方法。
  4. 透過結合適當的類別名稱的 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 類別互動:

  1. <TopAppBar />透過 className 道具來標記特定元件。
  2. 透過 addClassremoveClass 執行的 Adapter 方法。
  3. <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 的示範網頁相同。示範頁面應如下所示:

3d983b98c2092e7a.png

6. 總結

在這個教學課程中,我們介紹瞭如何包裝 MDC Web 的 Foundation,以便用於 React 應用程式。GitHub 和 npm 中的幾個程式庫會包裝 MDC Web 元件,如整合至架構中所述。建議你使用這裡的清單。除了 React 以外,這份清單也提供其他架構,例如 Angular 和 Vue。

本教學課程將重點說明我們決定將 MDC 網頁程式碼分為 3 個部分:FoundationAdapter元件。此架構讓元件可共用通用程式碼,同時與所有架構搭配使用。感謝您試用 Material Design 元件 React,並瞭解我們新推出的 MDC React 程式庫。希望您喜歡本程式碼研究室!

我可以在合理的時間內,完成本程式碼研究室

我想日後繼續使用 Material Design 元件