MDC-112 Web: Tích hợp MDC với Khung web

MDC-112 Web:
Tích hợp MDC với Khung web

Thông tin về lớp học lập trình này

subjectLần cập nhật gần đây nhất: thg 10 11, 2020
account_circleTác giả: Liz Mitchell, Abhinay Omkar

1. Giới thiệu

logo_components_color_2x_web_96dp.png

Thành phần Material (MDC) giúp nhà phát triển triển khai Material Design. Được tạo bởi một nhóm các kỹ sư và nhà thiết kế trải nghiệm người dùng tại Google, MDC có nhiều thành phần giao diện người dùng đẹp mắt, dễ sử dụng và có sẵn cho Android, iOS, web và Flutter.material.io/develop

MDC Web được thiết kế để tích hợp vào bất kỳ khung giao diện người dùng nào mà vẫn tuân thủ các nguyên tắc của Material Design. Lớp học lập trình sau đây hướng dẫn bạn cách xây dựng một Thành phần React, trong đó sử dụng MDC Web làm nền tảng. Các nguyên tắc đã học trong lớp học lập trình này có thể áp dụng cho mọi khung JavaScript.

Cách MDC Web được xây dựng

Lớp JavaScript của MDC Web bao gồm 3 lớp cho mỗi thành phần: Component (Thành phần), FoundationAdapter. Mẫu này giúp MDC Web linh hoạt tích hợp với các khung giao diện người dùng.

Nền tảng chứa logic kinh doanh giúp triển khai Material Design. Foundation không tham chiếu bất kỳ phần tử HTML nào. Điều này cho phép chúng tôi tóm tắt logic tương tác HTML vào Trình chuyển đổi. Nền tảng có một Bộ chuyển đổi.

Bộ chuyển đổi là một giao diện. Giao diện Bộ chuyển đổi được tham chiếu theo Nền tảng để triển khai logic kinh doanh Material Design. Bạn có thể triển khai Trình chuyển đổi trong nhiều khung như Angular hoặc React. Việc triển khai Bộ chuyển đổi sẽ tương tác với cấu trúc DOM.

Thành phầnNền tảng và vai trò của nền tảng là

  1. Triển khai Trình chuyển đổi, dùng JavaScript không phải khung và
  2. Cung cấp các phương thức công khai đại diện cho các phương thức trong Nền tảng.

Những lợi ích mà MDC Web cung cấp

Mỗi gói trong MDC Web đều đi kèm với một Thành phần, Nền tảngBộ chuyển đổi. Để tạo thực thể cho một Thành phần, bạn phải truyền phần tử gốc đến phương thức hàm khởi tạo của Thành phần đó. Thành phần triển khai Trình chuyển đổi, có khả năng tương tác với các phần tử DOM và HTML. Sau đó, Component (Thành phần) sẽ tạo thực thể cho Foundation. Nền tảng này sẽ gọi phương thức Adapter.

Để tích hợp MDC Web vào một khung, bạn cần tạo Thành phần của riêng mình bằng ngôn ngữ/cú pháp của khung đó. Khung Thành phần triển khai Bộ chuyển đổi của MDC Web và sử dụng Nền tảng của MDC Web.

Sản phẩm bạn sẽ tạo ra

Lớp học lập trình này minh hoạ cách tạo Trình chuyển đổi tuỳ chỉnh nhằm sử dụng logic Foundation (Nền tảng) để đạt được Thành phần phản ứng Material Design. Tài liệu này trình bày các chủ đề nâng cao trong bài viết Tích hợp vào các khung. React được dùng trong lớp học lập trình này làm khung mẫu, nhưng cũng có thể áp dụng cho bất kỳ khung nào khác.

Trong lớp học lập trình này, bạn sẽ xây dựng Thanh ứng dụng trên cùng và tạo lại trang minh hoạ của thanh ứng dụng trên cùng. Bố cục trang minh hoạ đã được thiết lập để bạn có thể bắt đầu làm việc trên Thanh ứng dụng trên cùng. Thanh ứng dụng trên cùng sẽ bao gồm:

  • Biểu tượng đi theo chỉ dẫn
  • Mục hành động
  • Có 4 biến thể có sẵn: biến thể Ngắn, luôn thu gọn, cố địnhnổi bật

Bạn cần:

  • Phiên bản gần đây của Node.js (đi kèm với npm, một trình quản lý gói JavaScript)
  • Mã mẫu (sẽ được tải xuống trong bước tiếp theo)
  • Kiến thức cơ bản về HTML, CSS, JavaScript và React

Bạn đánh giá thế nào về mức độ kinh nghiệm của mình trong lĩnh vực phát triển web?

2. Thiết lập môi trường nhà phát triển

Tải ứng dụng khởi đầu của lớp học lập trình

Ứng dụng khởi đầu này nằm trong thư mục material-components-web-codelabs-master/mdc-112/starter.

...hoặc sao chép tệp trên GitHub

Để sao chép lớp học lập trình này từ GitHub, hãy chạy các lệnh sau:

git clone https://github.com/material-components/material-components-web-codelabs
cd material
-components-web-codelabs/mdc-112/starter

Cài đặt các phần phụ thuộc của dự án

Trong thư mục khởi đầu material-components-web-codelabs/mdc-112/starter, hãy chạy:

npm install

Bạn sẽ thấy nhiều hoạt động và cuối cùng, thiết bị đầu cuối sẽ hiển thị cài đặt thành công:

22a33efc2a687408.pngS

Chạy ứng dụng khởi đầu

Trong cùng một thư mục, hãy chạy:

npm start

webpack-dev-server sẽ bắt đầu. Trỏ trình duyệt của bạn đến http://localhost:8080/ để xem trang.

b55c66dd400cf34f.png

Thành công! Mã khởi đầu cho trang Bản minh hoạ phản ứng của thanh ứng dụng trên cùng phải đang chạy trong trình duyệt của bạn. Bạn sẽ thấy một bức tường văn bản lorem ipsum, hộp Controls (Chế độ điều khiển) (ở dưới cùng bên phải) và một thanh ứng dụng trên cùng chưa hoàn tất:

4ca3cf6d216f9290.pngS

Xem mã và dự án

Nếu bạn mở trình soạn thảo mã, thư mục dự án sẽ có dạng như sau:

e9a3270d6a67c589.png

Mở tệp App.js và xem phương thức render, bao gồm cả Thành phần <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>
    );
  }

Đây là điểm truy cập cho TopAppBar trong ứng dụng.

Mở tệp TopAppBar.js là một lớp React Component đơn thuần bằng phương thức render:

TopAppBar.js

import React from 'react';

export default class TopAppBar extends React.Component {
 
render() {
   
return (
     
<header>
       
TOP APP BAR
     
</header>
   
);
 
}
}

3. Cấu trúc của thành phần

Trong React, phương thức render sẽ xuất ra HTML của Thành phần. Thành phần trên cùng của thanh ứng dụng sẽ kết xuất thẻ <header /> và bao gồm 2 phần chính:

  1. Biểu tượng điều hướng và phần tiêu đề
  2. Phần biểu tượng thao tác

Nếu bạn có thắc mắc về các phần tử tạo nên Thanh ứng dụng hàng đầu, hãy xem tài liệu trên GitHub.

Sửa đổi phương thức render() trong TopAppBar.js thành như sau:

  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>
    );
  }

Có hai phần tử mục trong HTML này. Nội dung đầu tiên chứa biểu tượng điều hướng và tiêu đề. Cửa sổ thứ hai chứa các biểu tượng hành động.

Tiếp theo, hãy thêm phương thức 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>
  );
}

Nhà phát triển sẽ nhập TopAppBar vào ứng dụng React và truyền các biểu tượng hành động vào phần tử TopAppBar. Bạn có thể xem mã mẫu khi khởi chạy TopAppBar trong App.js.

Thiếu phương thức getMergedStyles, phương thức này được dùng trong phương thức render. Vui lòng thêm phương thức JavaScript sau đây vào lớp TopAppBar:

getMergedStyles = () => {
  const {style} = this.props;
  const {style: internalStyle} = this.state;
  return Object.assign({}, internalStyle, style);
}

this.classes cũng bị thiếu trong phương thức render, nhưng sẽ được đề cập trong phần sau. Ngoài phương thức getter bị thiếu, this.classes, bạn vẫn cần triển khai một số phần của TopAppBar trước khi Thanh ứng dụng trên cùng có thể hiển thị chính xác.

Sau đây là các phần của Thành phần React vẫn còn thiếu trong Top App Bar:

  • Nền tảng ban đầu
  • Các phương thức chuyển đổi để truyền vào nền tảng
  • Mã đánh dấu JSX
  • Quản lý biến thể (cố định, ngắn, luôn thu gọn, nổi bật)

Phương pháp tiếp cận

  1. Triển khai các phương thức Adapter.
  2. Khởi động Foundation (Nền tảng) trong componentDidMount.
  3. Gọi phương thức Foundation.destroy trong componentWillUnmount.
  4. Thiết lập khả năng quản lý biến thể thông qua một phương thức getter kết hợp các tên lớp phù hợp.

4. Triển khai các phương thức của Trình chuyển đổi

Thành phần TopAppBar không khung của JS sẽ triển khai các phương thức Adapter sau (được liệt kê chi tiết tại đây):

  • hasClass()
  • addClass()
  • removeClass()
  • registerNavigationIconInteractionHandler()
  • deregisterNavigationIconInteractionHandler()
  • notifyNavigationIconClicked()
  • setStyle()
  • getTopAppBarHeight()
  • registerScrollHandler()
  • deregisterScrollHandler()
  • registerResizeHandler()
  • deregisterResizeHandler()
  • getViewportScrollY()
  • getTotalActionItems()

Vì React có sự kiện tổng hợp cũng như nhiều mẫu và phương pháp lập trình hay nhất khác nhau, nên bạn cần triển khai lại phương thức Adapter.

Phương thức getter của bộ chuyển đổi

Trong tệp TopAppBar.js, hãy thêm phương thức JavaScript sau đây vào 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,
  };
}

Các API bộ chuyển đổi để đăng ký sự kiện cuộn và thay đổi kích thước được triển khai giống hệt với phiên bản JS không phải khung, vì React không có bất kỳ sự kiện tổng hợp nào để cuộn hoặc đổi kích thước và tuân theo hệ thống sự kiện DOM gốc. getViewPortScrollY cũng cần phải tuân theo DOM gốc vì đây là một hàm trên đối tượng window và không có trong API của React. Quá trình triển khai bộ chuyển đổi sẽ khác nhau tuỳ theo từng khung.

Bạn có thể nhận thấy this.setStyle bị thiếu, được gọi bằng phương thức get adapter. Trong tệp TopAppBar.js, hãy thêm phương thức JavaScript bị thiếu vào lớp TopAppBar:

setStyle = (varName, value) => {
  const updatedStyle = Object.assign({}, this.state.style);
  updatedStyle[varName] = value;
  this.setState({style: updatedStyle});
}

Bạn vừa triển khai Trình chuyển đổi! Xin lưu ý rằng tại thời điểm này, bạn có thể thấy lỗi trong bảng điều khiển vì quá trình triển khai đầy đủ chưa hoàn tất. Phần tiếp theo sẽ hướng dẫn bạn cách thêm và xoá các lớp CSS.

5. Triển khai các phương thức của Thành phần

Quản lý biến thể và lớp

React không có API để quản lý lớp. Để bắt chước các phương thức thêm/xoá CSS lớp của JavaScript gốc, hãy thêm biến trạng thái classList. Có 3 đoạn mã trong TopAppBar tương tác với các lớp CSS:

  1. Thành phần <TopAppBar /> thông qua thuộc tính className.
  2. Phương thức Adapter thông qua addClass hoặc removeClass.
  3. Mã hoá cứng trong Thành phần React <TopAppBar />.

Trước tiên, hãy thêm lệnh nhập sau vào đầu TopAppBar.js, bên dưới các lệnh nhập hiện có:

import classnames from 'classnames';

Sau đó, hãy thêm mã sau vào phần khai báo lớp của Thành phần 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,
    });
  }

  ...
}

Nếu bạn truy cập vào http://localhost:8080, các hộp đánh dấu Controls (Kiểm soát) giờ đây sẽ bật/tắt tên lớp từ DOM.

Mã này giúp nhiều nhà phát triển có thể sử dụng TopAppBar. Các nhà phát triển có thể tương tác với API TopAppBar mà không phải lo lắng về chi tiết triển khai của các lớp CSS.

Hiện bạn đã triển khai thành công Trình chuyển đổi. Phần tiếp theo sẽ hướng dẫn bạn tạo thực thể cho Nền tảng.

Gắn và tháo thành phần

Quá trình tạo thực thể nền diễn ra trong phương thức componentDidMount.

Trước tiên, hãy nhập nền tảng Thanh ứng dụng trên cùng của MDC bằng cách thêm nội dung nhập sau đây sau các lệnh nhập hiện có trong TopAppBar.js:

import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';

Tiếp theo, hãy thêm mã JavaScript sau vào lớp 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();
  }
 
  ...

}

Một phương pháp lập trình React hiệu quả là xác định propTypes và defaultProps. Thêm nội dung nhập sau vào sau các lệnh nhập hiện có trong TopAppBar.js:

import PropTypes from 'prop-types';

Sau đó, hãy thêm mã sau vào cuối TopAppBar.js (sau lớp 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,
};

Lúc này, bạn đã triển khai thành công Thành phần phản ứng của thanh ứng dụng trên cùng. Nếu chuyển đến http://localhost:8080, bạn có thể phát qua trang minh hoạ. Trang minh hoạ sẽ hoạt động giống như trang minh hoạ của MMDC Web. Trang minh hoạ sẽ có dạng như sau:

3d983b98c2092e7a.pngS

6. Tóm tắt

Trong hướng dẫn này, chúng ta đã đề cập đến cách gói Nền tảng của MDC Web để sử dụng trong ứng dụng React. Có một số thư viện trên GitHub và npm bao bọc Thành phần web MDC như mô tả trong phần Tích hợp vào khung. Bạn nên sử dụng danh sách có tại đây. Danh sách này cũng bao gồm các khung khác ngoài React như Angular và Vue.

Hướng dẫn này nêu bật quyết định chia mã web MDC thành 3 phần: Foundation (Nền tảng), Adapter (Bộ chuyển đổi) và Component (Thành phần). Cấu trúc này cho phép các thành phần chia sẻ mã chung trong khi làm việc với tất cả khung. Cảm ơn bạn đã dùng thử thành phần Material React và vui lòng dùng thử thư viện mới của chúng tôi có tên MDC React. Chúng tôi hy vọng bạn thích lớp học lập trình này!

Tôi đã có thể hoàn thành lớp học lập trình này với khá nhiều thời gian và công sức

Tôi muốn tiếp tục sử dụng Thành phần Material trong tương lai