Ant Design Pro V5開發指南


Ant Design Pro 是一個基於 umi、dva 和 ant design 的開箱即用的中台前端/設計解決方案。

一、umi和dva

1.1、什么是umi

umi,中文可發音為烏米,是一個可插拔的企業級 react 應用框架。umi 以路由為基礎的,支持類 next.js 的約定式路由,以及各種進階的路由功能,並以此進行功能擴展,比如支持路由級的按需加載。然后配以完善的插件體系,覆蓋從源碼到構建產物的每個生命周期,支持各種功能擴展和業務需求,目前內外部加起來已有 50+ 的插件。

上面一段來自umi官網介紹,從上面我們得到一個重要信息,umi的一個重要功能就是路由配置。 此外umi整合了webpack的功能,umi相比webpack增加了運行時的能力,同時幫助我們配置了很多 webpack 的預設。也減少了 webpack 升級導致的問題:

1.2、什么是dva

dva 首先是一個基於 redux 和 redux-saga 的數據流方案,可以和umi完美結合。

1.3、 什么是redux-saga

redux-saga是一個用於管理應用程序 Side Effect(副作用,例如異步獲取數據,訪問瀏覽器緩存等)的 library,它的目標是讓副作用管理更容易,執行更高效,測試更簡單,在處理故障時更容易。

可以想像為,一個 saga 就像是應用程序中一個單獨的線程,它獨自負責處理副作用。redux-saga是一個 redux 中間件,意味着這個線程可以通過正常的 redux action 從主應用程序啟動,暫停和取消,它能訪問完整的 redux state,也可以 dispatch redux action。

redux-saga 使用了 ES6 的 Generator 功能,讓異步的流程更易於讀取,寫入和測試。(如果你還不熟悉的話,這里有一些介紹性的鏈接 通過這樣的方式,這些異步的流程看起來就像是標准同步的 Javascript 代碼。(有點像 async/await,但 Generator 還有一些更棒而且我們也需要的功能)。

你可能已經用了 redux-thunk 來處理數據的讀取。不同於 redux thunk,你不會再遇到回調地獄了,你可以很容易地測試異步流程並保持你的 action 是干凈的。

1.3.1 安裝

npm install --save redux-saga

1.3.2 使用示例

假設我們有一個 UI 界面,在單擊按鈕時從遠程服務器獲取一些用戶數據(為簡單起見,我們只列出 action 觸發代碼)。

class UserComponent extends React.Component { ... onSomeButtonClicked() { const { userId, dispatch } = this.props dispatch({type: 'USER_FETCH_REQUESTED', payload: {userId}}) } ... }

這個組件 dispatch 一個 plain Object 的 action 到 Store。我們將創建一個 Saga 來監聽所有的 USER_FETCH_REQUESTED action,並觸發一個 API 調用獲取用戶數據。

sagas.js:

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects' import Api from '...'

// worker Saga : 將在 USER_FETCH_REQUESTED action 被 dispatch 時調用
function* fetchUser(action) { try { const user = yield call(Api.fetchUser, action.payload.userId); yield put({type: "USER_FETCH_SUCCEEDED", user: user}); } catch (e) { yield put({type: "USER_FETCH_FAILED", message: e.message}); } } /* 在每個 `USER_FETCH_REQUESTED` action 被 dispatch 時調用 fetchUser 允許並發(譯注:即同時處理多個相同的 action) */
function* mySaga() { yield takeEvery("USER_FETCH_REQUESTED", fetchUser); } /* 也可以使用 takeLatest 不允許並發,dispatch 一個 `USER_FETCH_REQUESTED` action 時, 如果在這之前已經有一個 `USER_FETCH_REQUESTED` action 在處理中, 那么處理中的 action 會被取消,只會執行當前的 */
function* mySaga() { yield takeLatest("USER_FETCH_REQUESTED", fetchUser); } export default mySaga;

為了能跑起 Saga,我們需要使用 redux-saga 中間件將 Saga 與 Redux Store 建立連接。

main.js:

import { createStore, applyMiddleware } from 'redux' import createSagaMiddleware from 'redux-saga' import reducer from './reducers' import mySaga from './sagas'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware() // mount it on the Store
const store = createStore( reducer, applyMiddleware(sagaMiddleware) ) // then run the saga
sagaMiddleware.run(mySaga) // render the application

更多使用細節請移步官網

二、腳手架使用

2.1、初始化腳手架

新建一個空的文件夾作為項目目錄,並在目錄下使用 create umi 來快速的初始化腳手架。

# 使用 npm npm create umi react-big-screen

如果下載比較慢,可以先配置npm阿里源:

npm config set registry https://registry.npm.taobao.org/

按照 umi 腳手架的引導,第一步先選擇 ant-design-pro:

? Select the boilerplate type (Use arrow keys) > ant-design-pro  - Create project with a layout-only ant-design-pro boilerplate, use together with umi block. app - Create project with a simple boilerplate, support typescript. block - Create a umi block. library - Create a library with umi. plugin - Create a umi plugin.

選擇 antd 的版本,4 或者 5,主意V5和V4差別較大,這里我選擇了V5。

? Select the boilerplate type ant-design-pro ? � Be the first to experience the new umi@3 ?
> Pro V5 Pro V4

安裝依賴:

cd react-big-screen && cnpm install

2.2、啟動腳手架

開啟 Umi UI(可選):

npm start

使用admin/ant.design登錄系統:

通過npm start我們就可以啟動服務,那你可能會好奇執行這個命令為什么就可以啟動我們的服務呢?

npm start 運行的是package.json中script塊start對應的命令,打開package.json,你會發現我們實際執行的是如下執行:

cross-env是用來解決多環境問題的,你可暫且忽略。重點關注umi dev。

umi  是一個軟連接到umi.js的文件:

#!/usr/bin/env node
 const resolveCwd = require('resolve-cwd'); const { name, bin } = require('../package.json'); const localCLI = resolveCwd.silent(`${name}/${bin['umi']}`);
if (!process.env.USE_GLOBAL_UMI && localCLI && localCLI !== __filename) { const debug = require('@umijs/utils').createDebug('umi:cli'); debug('Using local install of umi'); require(localCLI); } else { require('../lib/cli'); }

也就是其實執行的umi/lib/cli.js文件,  關鍵部分代碼:

_asyncToGenerator(function* () { try { switch (args._[0]) { case 'dev': const child = (0, _fork.default)({ scriptPath: require.resolve('./forkedDev') }); // ref:
        // http://nodejs.cn/api/process/signal_events.html
        // https://lisk.io/blog/development/why-we-stopped-using-npm-start-child-processes
 process.on('SIGINT', () => { child.kill('SIGINT'); // ref:
          // https://github.com/umijs/umi/issues/6009
 process.exit(0); }); process.on('SIGTERM', () => { child.kill('SIGTERM'); process.exit(1); }); break; default: const name = args._[0]; if (name === 'build') { process.env.NODE_ENV = 'production'; } yield new _ServiceWithBuiltIn.Service({ cwd: (0, _getCwd.default)(), pkg: (0, _getPkg.default)(process.cwd()) }).run({ name, args }); break; } } catch (e) { console.error(_utils().chalk.red(e.message)); console.error(e.stack); process.exit(1); } })();

三、頁面布局調整

運行程序,我們發現菜單默認是位於側邊欄的,如果我們想將菜單是置於頂部的。因此我們需要進行布局的修改。

在修改之前,我們了解到為了降低研發成本,Ant Design Pro將布局通過umi插件 @umijs/plugin-layout 的方式內置,我們只需要通過簡單的配置就可以修改Ant Design的Layout,包括導航以及側邊欄。

plugin-layout 插件主要提供了以下功能:

  • 默認為 Ant Design 的 Layout @ant-design/pro-layout,支持它全部配置項。
  • 側邊欄菜單數據根據路由中的配置自動生成。
  • 默認支持對路由的 403/404 處理和 Error Boundary。
  • 搭配 @umijs/plugin-access 插件一起使用,可以完成對路由權限的控制。
  • 搭配 @umijs/plugin-initial-state 插件和 @umijs/plugin-model 插件一起使用,可以擁有默認用戶登陸信息的展示。

3.1、修改config/config.ts

可以通過修改配置文件配置 layout的主題、菜單等樣式, 修改config/config.ts:

import { Settings as LayoutSettings } from '@ant-design/pro-layout'; //pro-layout布局配置重寫,更多參數配置參考;https://github.com/ant-design/ant-design-pro-layout
const Settings: LayoutSettings & { pwa?: boolean; logo?: string; } = { navTheme: 'dark',             //整體風格設置 light、dark
  // 拂曉藍
  primaryColor: '#1890ff',       //主題色
  layout: 'top',                //導航模式 side、top、mix
  contentWidth: 'Fluid',        //內容區域寬度:流式Fluid、定寬Fixed
  fixedHeader: false,           //固定header
  fixSiderbar: true,            //固定側邊測但
  colorWeak: false,             //色弱模式
  title: '報警管理平台', pwa: false, logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', iconfontUrl: '', }; export default Settings;

此時,頁面布局如下:

3.2、pro-components

ant-design/pro-layout 已經遷移至 ant-design/pro-components 倉庫進行后續的維護,訪問 https://procomponent.ant.design/layout 可以了解更多信息。

ProComponents 是基於 Ant Design 而開發的模板組件,提供了更高級別的抽象支持,開箱即用。其中ProComponets封裝了頁面布局相關的組件,這些組件來自於ant-design/pro-layout ,主要包括ProLayout、PageContainer、GridContent、FooterToolbar、SettingDrawer、SiderMenu、TopNavHeader等。

而我們配置的config/config.ts這些信息,會被這些布局組件所使用。具體實現可以查看源碼

3.3、SettingDrawer(只針對V5版本,其他把版本查看官方文檔)

從官網下載的代碼默認是不支持主題切換的,如果想支持主題切換需要安裝以下依賴:

cnpm install   umi-plugin-setting-drawer --save-dev cnpm install umi-plugin-antd-theme  --save-dev

最新版本如下:

"umi-plugin-antd-theme": "^2.1.2", "umi-plugin-setting-drawer": "^1.0.3"

同時需要配置主題相關信息config/theme.config.json:

{ "theme": [ { "key": "dark", "fileName": "dark.css", "theme": "dark", "modifyVars": { "dark": true } }, { "key": "dust", "fileName": "dust.css", "modifyVars": { "@primary-color": "#F5222D" } }, { "key": "volcano", "fileName": "volcano.css", "modifyVars": { "@primary-color": "#FA541C" } }, { "key": "sunset", "fileName": "sunset.css", "modifyVars": { "@primary-color": "#FAAD14" } }, { "key": "cyan", "fileName": "cyan.css", "modifyVars": { "@primary-color": "#13C2C2" } }, { "key": "green", "fileName": "green.css", "modifyVars": { "@primary-color": "#52C41A" } }, { "key": "geekblue", "fileName": "geekblue.css", "modifyVars": { "@primary-color": "#2F54EB" } }, { "key": "purple", "fileName": "purple.css", "modifyVars": { "@primary-color": "#722ED1" } }, { "key": "dust", "theme": "dark", "fileName": "dark-dust.css", "modifyVars": { "@primary-color": "#F5222D", "dark": true } }, { "key": "volcano", "theme": "dark", "fileName": "dark-volcano.css", "modifyVars": { "@primary-color": "#FA541C", "dark": true } }, { "key": "sunset", "theme": "dark", "fileName": "dark-sunset.css", "modifyVars": { "@primary-color": "#FAAD14", "dark": true } }, { "key": "cyan", "theme": "dark", "fileName": "dark-cyan.css", "modifyVars": { "@primary-color": "#13C2C2", "dark": true } }, { "key": "green", "theme": "dark", "fileName": "dark-green.css", "modifyVars": { "@primary-color": "#52C41A", "dark": true } }, { "key": "geekblue", "theme": "dark", "fileName": "dark-geekblue.css", "modifyVars": { "@primary-color": "#2F54EB", "dark": true } }, { "key": "purple", "theme": "dark", "fileName": "dark-purple.css", "modifyVars": { "@primary-color": "#722ED1", "dark": true } } ], "min": true, "isModule": true, "ignoreAntd": false, "ignoreProLayout": false, "cache": true, "extraLibraries": [ "@ant-design/pro-form", "@ant-design/pro-descriptions", "@ant-design/pro-field", "@ant-design/pro-list", "@ant-design/pro-card", "@ant-design/pro-provider", "@ant-design/pro-skeleton", "@ant-design/pro-utils" ] }
  • extraLibraries:@antd-design/pro-xxx ;  antd-pro-merge-less 在生成樣式文件時,會加載該指定包中樣式文件(特別需要注意的是antd-pro-merge-less 默認只加載了antd pro組件 @ant-design/pro-table、@ant-design/pro-form的樣式);

  • ignoreAntd:在生成樣式文件時,是否加載antd樣式文件

  • cache:是否開啟緩存,通過比較樣式和antd-pro-merge-less/.temp/temp.less文件的hash,判斷文件是否需要重新生成,這樣就不會在每次啟動的時候重新生成樣式文件

umi-plugin-antd-theme會根據遍歷這個配置文件,動態的在node_modules\.plugin-theme\theme下生成的對應的樣式文件。

最終在點擊SettingDrawer組件進行樣式調整的時候,實際就是給動態body加入樣式文件的過程 :

<link type="text/css" rel="stylesheet" id="theme-style" href="/theme/volcano.css">

我們也可以將樣式文件復制到/public/theme/下。

如果我們不想使用SettingDrawer組件,需要把package.json devDependencies中的這兩個包排除。

SettingDrawer組件中的主題色ThemeColor 用於展示當前可選的主色,色彩列表themeList由 umi-plugin-antd-theme 插件提供,該插件會將一個色彩列表放到 window.umi_plugin_ant_themeVar 變量上,SettingDrawer 會讀取這個變量並給到 ThemeColor。

<ThemeColor value={primaryColor} colors={ hideColors ? [] : themeList.colorList[navTheme === 'realDark' ? 'dark' : 'light'] } formatMessage={formatMessage} onChange={(color) => changeSetting('primaryColor', color, hideLoading) } />

3.4、 umi-plugin-antd-theme 插件流程分析

這里只粗略介紹一下具體流程、不做細致的代碼分析,感興趣的請閱讀源碼。

  1. 更改 cssLoader 配置,修改 src 目錄下less 文件CSS Modules選擇器名稱

  2. 加載工程固定路徑下主題配置文件 config/theme.config.json覆蓋默認配置(如果配置為空,也就是使用組件原始配置樣式)

  3. 設置dev環境臨時主題色文件路徑為 node_modules/.plugin-theme/theme

  4. 設置serve-static中間件,允許訪問臨時主題色文件

  5. 將主題色配置信息掛載在 window.umi_plugin_ant_themeVar

  6. dev環境 onDevCompileDone

如果存在臨時文件,則刪除

創建 .plugin-theme/theme

遍歷config/theme.config.json下每個主題色,使用 antd-pro-merge-less包 buildCss 至 .plugin-theme/theme 每一個主題色,生成一個 css 文件 prod 環境與 dev 環境的差異體現在生產的文件生成在 dist/theme 目錄下

3.5、antd-pro-merge-less 插件流程分析

  1. 設置臨時文件目錄antd-pro-merge-less/.temp

  2. 使用 glob 找到 antd-pro-merge-less 項目下所有的 less 文件路徑

  3. 將所有less文件內容寫入antd-pro-merge-less/.temp/temp.less以及antd-pro-merge-less/.temp/pro.less

  4. 如果config/theme.config.json配置"ignoreAntd": false,則還會導入antd模塊下的所有less文件(需要注意的是如果沒有配置dark:true, 不會加載themes/dark.less,themes/compack.less),到 ./antd.less

  5. 將@import './antd'導入./components.less文件,同時還會根據extraLibraries配置導入antd design pro組件的樣式文件

  6. 提取import文件的變量,刪除 import ,寫入antd-pro-merge-less/.temp/pro.less ,並引用 @import './components'

  7. 將依賴的 antd 相關組件的 less 文件寫入./components.less 開始遍歷不同的顏色配置,根據不同配置生成 antd less 文件

  8. 使用 less 將 pro.less 文件轉化為 css 文件,並替換變量

常見錯誤處理:

1、如果運行出現錯誤 檢查node_modules\_antd-pro-merge-less@xxx@antd-pro-merge-less\loopAllLess.js文件,修改文件最后為:

return Promise.resolve(
// prettier.format(content, {
//   parser: 'less',
// }),
content
);

因為prettier.format在格式化less文件時會將 :

@pro-global-footer-prefix-cls: ~'@{ant-prefix}-pro-global-footer' 轉為 
@pro-global-footer-prefix-cls ~'@
{ant-prefix}-pro-global-footer'

2、@ant-deisign/pro-card組件存在Bug  _@ant-design_pro-card@1.11.7@@ant-design\pro-card\es\components\Statistic\index.less

.@{ant-prefix}-statistic-title { color: @text-color; # 將之前的固定色rgba(00,00,00,0.45)修改成變量 }

3、強制重新生成樣式文件

  • 如果config/theme.config.json配置中開啟了緩存cache,如果想強制重新生成樣式文件,刪除antd-pro-merge-less\.temp\temp.less文件,重新運行
  • 設置cache為false關閉緩存

4、antd pro V5 中,css文件重復打包

直接在V5的Demo頁面多次點擊菜單來切換路由,會發現樣式會有多次覆蓋的情況。
https://preview.pro.ant.design/dashboard/analysis?fixSiderbar=true&colorWeak=false&pwa=false
image

目前是參考 https://umijs.org/zh-CN/config#chainwebpack ,修改了打包規則,config.ts中增加以下配置,解決了這個問題:

chunks: ['vendors', 'umi'],
  chainWebpack: function (config, { webpack }) {
    config.merge({
      optimization: {
        splitChunks: {
          chunks: 'all',
          minChunks: 2,
          automaticNameDelimiter: '.',
          cacheGroups: {
            vendor: {
              name: 'vendors',
              test({ resource }) {
                return /[\\/]node_modules[\\/]/.test(resource);
              },
              priority: 10,
            },
          },
        },
      },
    });
  },

四、新增頁面步驟

這里的『頁面』指配置了路由,能夠通過鏈接直接訪問的模塊,要新建一個頁面,通常只需要在腳手架的基礎上進行簡單的配置。

4.1、新增js、less文件

在src/pages下創建新的js、less文件。如果又多個相關頁面,可以創建一個新文件夾來放置相關文件。

config src models pages + NewPage.js + NewPage.less ... ... package.json

為了更好的演示,我們初始化NewPage.js的內容如下:

export default () => { return <div>New Page</div>;
};

暫時不向本文檔中的樣式文件添加內容,您也可以嘗試自己添加內容。 樣式文件默認使用CSS Modules,如果需要,可以導入antd less 變量 在文件的頭部:

@import '~antd/lib/style/themes/default.less';

這樣可以輕松獲取 antd 樣式變量並在文件中使用它們,這可以保持保持頁面的一致性,並有助於實現自定義主題。

4.2、將文件加入菜單和路由

加入菜單和路由的方式請參照 路由和菜單 - 添加路由/菜單 中的介紹完成。加好后,訪問 http://localhost:8000/#/new 就可以看到新增的頁面了。

4.3、新增model、service

布局及路由都配置好之后,回到之前新建的 NewPage.js,可以開始寫業務代碼了!

如果需要用到 dva 中的數據流,還需要在 src/models src/services 中建立相應的 model 和 service,具體可以參考腳手架內置頁面的寫法。不過我們更加推薦使用輕量數據流管理數據,並且使用 openAPI 插件來生成 serves。

五、代碼下載

5.1、開發計划

接下來我將花一段時間開發一個監控平台:

5.2、代碼下載

代碼下載地址:https://github.com/Zhengyang550/react-big-screen


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM