對於學習過程,不是特別建議從一開始就使用別人的第三方庫UI庫,更重要的是要學會組件化相關的知識(就想前面我們已經講了非常相關知識),之後自己來封裝、設計一套自己的可複用組件。

但是在公司開發爲了開發效率,我們往往也會選擇一些非常優秀的第三方UI庫,而AntDesign就是這樣的一套優秀的UI組件庫。

一. 認識AntDesign

1.1. AntDesign的介紹

AntDesign ,簡稱 antd 是基於 Ant Design 設計體系的 React UI 組件庫,主要用於研發企業級中後臺產品。

AntDesign的特點:

  • :rainbow: 提煉自企業級中後臺產品的交互語言和視覺風格。

  • :package: 開箱即用的高質量 React 組件。

  • 使用 TypeScript 開發,提供完整的類型定義文件。

  • ⚙️ 全鏈路開發和設計工具體系。

  • :earth_africa: 數十個國際化語言支持。

  • :art: 深入每個細節的主題定製能力。

全鏈路開發和設計指的是什麼?

  • 全鏈路這個詞我記得是16年左右阿里提出的;

  • 業務戰略—用戶場景—設計目標—交互體驗—用戶流程—預期效率 全方面進行分析和考慮;
  • 這個主要是產品經理會考慮的一個點;

AntDesign的兼容性:

  • 現代瀏覽器和 IE11(需要 polyfills)。

  • 支持服務端渲染。

  • Electron

瀏覽器兼容

[email protected] 之後不再支持 IE8, [email protected] 之後不再支持 IE9/10。

目前穩定的版本:v4.4.0

1.2. AntDesign的安裝

使用 npm 或 yarn 安裝

npm安裝:

npm install antd --save

yarn安裝:

yarn add antd

我們需要在index.js中引入全局的Antd樣式:

import "antd/dist/antd.css";

在App.js中就可以使用一些組件了:

antd的使用

考慮一個問題:Antd是否會將一些沒有用的代碼(組件或者邏輯代碼)引入,造成包很大呢?

antd 官網有提到: antd 的 JS 代碼默認支持基於 ES modules 的 tree shaking,對於 js 部分,直接引入 import { Button } from 'antd' 就會有按需加載的效果。

1.3. 高級配置

1.3.1. 認識craco

上面的使用過程是無法對主題進行配置的,好像對主題等相關的高級特性進行配置,需要修改create-react-app 的默認配置。

如何修改create-react-app 的默認配置呢?

  • 前面我們講過,可以通過 yarn run eject 來暴露出來對應的配置信息進行修改;
  • 但是對於webpack並不熟悉的人來說,直接修改 CRA 的配置是否會給你的項目帶來負擔,甚至會增加項目的隱患和不穩定性呢?

  • 所以,在項目開發中是不建議大家直接去修改 CRA 的配置信息的;

那麼如何來進行修改默認配置呢?社區目前有兩個比較常見的方案:

  • react-app-rewired + customize-cra;(這個是antd早期推薦的方案)

  • craco;(目前antd推薦的方案)

第一步:安裝craco:

yarn add @craco/craco

第二步:修改package.json文件

  • 原本啓動時,我們是通過react-scripts來管理的;

  • 現在啓動時,我們通過craco來管理;

"scripts": {
-   "start": "react-scripts start",
-   "build": "react-scripts build",
-   "test": "react-scripts test",
+   "start": "craco start",
+   "build": "craco build",
+   "test": "craco test",
}

第三步:在根目錄下創建craco.config.js文件用於修改默認配置

module.exports = {
  // 配置文件
}

1.3.2. 配置主題

按照 配置主題 的要求,自定義主題需要用到類似 less-loader 提供的 less 變量覆蓋功能:

  • 我們可以引入 craco-less 來幫助加載 less 樣式和修改變量;

安裝 craco-less

yarn add craco-less

修改craco.config.js中的plugins:

  • 使用 modifyVars 可以在運行時修改LESS變量;
const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
}

引入antd的樣式時,引入antd.less文件:

// import "antd/dist/antd.css";
import 'antd/dist/antd.less';

修改後重啓 yarn start ,如果看到一個綠色的按鈕就說明配置成功了。

1.3.3. 配置別名

在項目開發中,某些組件或者文件的層級會較深,

  • 如果我們通過上層目錄去引入就會出現這樣的情況: ../../../../components/button

  • 如果我們可以配置別名,就可以直接從根目錄下面開始查找文件: @/components/button ,甚至是: components/button

配置別名也需要修改webpack的配置,當然我們也可以藉助於 craco 來完成:

...

const path = require("path");
const resolve = dir => path.resolve(__dirname, dir);

module.exports = {
  ...
  ,
  webpack: {
    alias: {
      '@': resolve("src"),
      'components': resolve("src/components"),
    }
  }
}

在導入時就可以按照下面的方式來使用了:

import HYCommentInput from '@/components/comment-input';
import HYCommentItem from 'components/comment-item';

二. AntDesign案例

我們通過AntDesign來編寫一個案例:

image-20200706111432484

1.1. 案例-評論框

我們選來完成評論框,評論框有兩部分組成:

  • TextArea的輸入框:Input.TextArea;

  • 提交評論的按鈕:Button;

import React, { PureComponent } from 'react';

import moment from 'moment';
import {
  Form, Button, Input
} from 'antd';

export default class HYCommentInput extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      value: ""
    }
  }

  render() {
    return (
      <div>
        <Input.TextArea rows={4} onChange={this.onChange.bind(this)} value={this.state.value} />
        <Button onClick={this.onSubmit.bind(this)} type="primary">
          添加評論
        </Button>
      </div>
    )
  }

  onChange(e) {
    this.setState({
      value: e.target.value
    })
  }

  onSubmit() {
    console.log(this.state.value, moment().fromNow());
    const commentInfo = {
      id: Date.now(),
      name: "coderwhy",
      avatar: "https://upload.jianshu.io/users/upload_avatars/1102036/c3628b478f06.jpeg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240",
      content: <p>{this.state.value}</p>,
      datetime: moment()
    }

    this.props.submitComment(commentInfo);
    this.setState({
      value: ""
    });
  }
}

1.2. 案例-評論列表

評論列表主要是使用Comment組件,Comment組件有一些屬性:

  • author:展示作者的名稱;

  • avatar:展示作者的頭像;

    • 可以使用Avatar的組件進行展示;

  • content:展示評論的內容;

  • datetime:展示評論的時間:

    • 這裏我們可以使用Tooltip組件,當鼠標放在上面時,會顯示對應的title內容;

  • actions:評論下方的操作按鈕;

    • 這裏我們可以使用DeleteOutlined,但是它來自 @ant-design/icons ,需要我們進行安裝;
import React, { PureComponent } from 'react';

import {
  Comment,
  Avatar,
  Tooltip
} from "antd";
import { DeleteOutlined } from "@ant-design/icons";

export default class HYCommentItem extends PureComponent {
  render() {
    const { comment } = this.props;

    return (
      <Comment
        author={<a href="/#">{comment.name}</a>}
        avatar={
          <Avatar
            src={comment.avatar}
            alt={comment.name}
          />
        }
        content={comment.content}
        datetime={
          <Tooltip title={comment.datetime.format('YYYY-MM-DD HH:mm:ss')}>
            <span>{comment.datetime.fromNow()}</span>
          </Tooltip>
        }
        actions={ this.getActions() }
      />
    )
  }

  getActions() {
    return [
      <span onClick={this.props.removeItem}><DeleteOutlined/> 刪除</span>
    ]
  }
}

1.3. 案例-App組件

我們在App組件中,使用封裝的兩個組件:

import React, { PureComponent } from 'react';

import HYCommentInput from './components/comment-input';
import HYCommentItem from './components/comment-item';

export default class App extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      commentList: []
    }
  }

  render() {
    return (
      <div style={{width: "500px", padding: "20px"}}>
        {
          this.state.commentList.map((item, index) => {
            return <HYCommentItem key={item.id} 
                                  comment={item} 
                                  index={index} 
                                  removeItem={e => this.removeItem(index)}/>
          })
        }
        <HYCommentInput submitComment={this.submitComment.bind(this)}/>
      </div>
    )
  }

  submitComment(comment) {
    this.setState({
      commentList: [...this.state.commentList, comment]
    })
  }

  removeItem(index) {
    const newCommentList = [...this.state.commentList];
    newCommentList.splice(index, 1);
    this.setState({
      commentList: newCommentList
    })
  }
}
相關文章