学习笔记
原文地址:antDesignPro使用心得,快速开发必备。
https://www.52pojie.cn/thread-696928-1-1.html
(出处: 吾爱破解论坛)
摘要介绍
Ant Design Pro
是一个基于Ant Design
搭建起来的模板项目。它提供了两个主要布局:BasicLayout
、UserLayout
,在布局基础上制作了20多个基础页面,详情见模板
介绍段落。
Ant Design Pro
主体代码使用ES2015+语法规则,因此在阅读源码时遇到不理解的语法,可前往相关主页进行查询。在学习笔记中,除非遇到关键的语法点,否则不对语法进行额外说明。
在接下来,将按照以下几个方面介绍项目的相关代码。
......
目录结构
├── mock # 本地模拟数据
├── node_modules # 依赖库
├── public
│ ├── favicon.ico # Favicon
│ └── index.html # HTML 入口模板
├── src
│ ├── common # 应用公用配置,如导航信息
│ ├── components # 业务通用组件
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # dva model
│ ├── routes # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── g2.js # 可视化图形配置
│ ├── polyfill.js # 兼容性垫片
│ ├── theme.js # 主题配置
│ ├── index.js # 应用入口
│ ├── index.less # 全局样式
│ └── router.js # 路由入口
├── tests # 测试工具
├── .editorconfig # 编辑器配置
├── .eslintrc # js代码检测工具
├── .ga # 未知
├── .gitignore # git版本配置
├── .roadhogrc # roadhog配置
├── .roadhogrc.mock.js # roadhog的模拟配置
├── .stylelintrc # css代码审查配置
├── .travis.yml # travis持续构建工具配置
├── package.json # web前端项目配置文件
├── README.md
└──
项目中的几项配置文件
Q:为什么要用
编辑器配置
?A:当多人共同开发一个项目的时候,往往会出现大家用不同编辑器的情况。就前端开发者来说,有人喜欢 Sublime,有人喜欢 Webstorm , 也有人喜欢 Atom,还有人喜欢 Vim,HBuilder 等等。各种不同编程语言的开发者喜欢各种不同的编辑器。问题来了,如何让使用不同编辑器的开发者在共同开发一个项目时“无痛”地遵循编码规范(编码风格)?
Q:怎么用
编辑器配置
?A:在项目根创建一个名为 .editorconfig 的文件。安装与编辑器对应的 EditorConfig 插件。详情参考编辑器配置
Q:
代码检查工具
是什么?A:js的代码检查工具是ESLint,css的代码检查工具是StyleLint,相应的配置项保存在
.eslintrc
和.stylelintrc
文件中。一般来说,都不需要进行修订,深入学习可参考js代码检测工具、css代码审查配置
Q:
git
是什么?A:
git
是版本控制工具,类似的工具还有svn
。有关.gitignore
的配置参考git版本配置
Q:什么是
持续集成系统
?A:对个人而言,就是让你的代码在提交到远程——这里是GitHub——后,立即自动编译,并且在失败后可以自动给你发邮件的东西。当然,除了编译,还能做自动化测试、自动部署等。对团队或企业而言,这意味着更多的东西,是敏捷开发的一种践行。
travis
是一种持续集成工具,企业中还有用jenkins
的。有关travis
的更多介绍见travis持续构建工具配置
Q:什么是
roadhog
?A:这是一个 cli 工具,提供
server
、build
和test
三个命令,分别用于本地调试和构建。更多介绍见roadhog配置
Q:web前端项目的配置是package?
A:每个web前端项目的根目录下面,一般都有一个
package.json
文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。更多介绍见web前端项目配置文件
Q:最关键,初学者应着重关心哪些?
A:初学者应将精力放在
package.json
、roadhog
这两者上,其他的都可以忽略掉。
package.json摘要介绍
npm install
命令根据这个package.json
配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。package.json
文件就是一个JSON对象,该对象的每一个成员就是当前项目的一项设置。
scripts
指定了运行脚本命令的npm命令行缩写,比如start指定了运行npm run start
时,所要执行的命令。
进行前端开发时可能经常用到的几个命令是:npm run start
(进行开发调试,缩写成npm start
)、npm run build
(进行构建打包)。当然也可以尝试package.json
中给出的其他命令,如:npm run analyze
、npm run test
等,甚至也可以自己在package.json
中添加需要的命令。
dependencies
字段指定了项目运行所依赖的模块,devDependencies
指定项目开发所需要的模块。它们都指向一个对象。该对象的各个成员,分别由模块名和对应的版本要求组成,表示依赖的模块及其版本范围。更多信息参见web前端项目配置文件
babel
配置项,其实是有关babel
的配置内容,写在package.json
中实际上是一种省略,也可以写在.babelrc
文件中。
lint-staged
是与代码检查有关的配置项,jest
是与单元测试有关的配置项。这两项的配置可以参考jest、lint。这两项与写业务逻辑代码没有直接关联。
roadhog摘要介绍
roadhog
是一个 cli 工具,提供 server
、 build
和 test
三个命令,分别用于本地调试和构建,并且提供了特别易用的 mock
功能。命令行体验和 create-react-app
一致,配置略有不同,比如默认开启 css modules
,然后还提供了 JSON
格式的配置方式。
重点介绍roadhog
有关的几个配置项,主要是在ant design pro
的代码中用到了这些配置项。
entry
指定 webpack
入口文件,支持 glob
格式。
如果你的项目是多页类型,会希望把 src/pages
的文件作为入口。可以这样配:
"entry": "src/pages/\*.js"
env
针对特定的环境进行配置。server
的环境变量是 development
,build
的环境变量是 production
。
比如:
"extraBabelPlugins": ["transform-runtime"],
"env": {
"development": {
"extraBabelPlugins": ["dva-hmr"]
}
}
这样,开发环境下的 extraBabelPlugins
是 ["transform-runtime", "dva-hmr"]
,而生产环境下是 ["transform-runtime"]
。
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr",
"transform-runtime",
"transform-decorators-legacy",
"transform-class-properties",
["import", { "libraryName": "antd", "style": true }]
]
},
"production": {
"extraBabelPlugins": [
"transform-runtime",
"transform-decorators-legacy",
"transform-class-properties",
["import", { "libraryName": "antd", "style": true }]
]
}
}
在这段代码中,开发环境和生产环境分别配置,其中开发环境使用了dva-hmr
插件,
externals
配置 webpack
的 externals
属性。
theme
配置主题,实际上是配 less
的 modifyVars
。支持 Object
和文件路径两种方式的配置。
比如:
"theme": {
"@primary-color": "#1DA57A"
}
或者,
"theme": "./node_modules/abc/theme-config.js"
这里有 如何配置 antd theme 的例子 。
babel
上述多处提到了babel
,因此有必要针对babel
进行了解。用官方的用语:Babel 是一个 JavaScript 编译器。今天就来用下一代 JavaScript 语法写代码吧!
。换句话说:Babel
是一个广泛使用的转码器,可以将ES6
代码转为ES5
代码,从而在现有环境执行。
既然如此,接下来重点说说package.json
、.roadhogrc
中有关babel
的配置内容:
presets
字段用来设定转码规则,如package.json
中
"babel": {
"presets": [
"env",
"react"
],
...
}
就是设定了env
、react
两个转码规则。其中env
指的是babel-preset-env,这是一个新的 preset
,可以根据配置的目标运行环境(environment
)自动启用需要的 babel
插件。react
指的是babel-preset-react,主要是针对所有react
插件的转码规则。
plugins
配置项不用多说,从名称就能看出来,就是babel
的一系列插件,与ant design pro
的package.json
相关的两个插件在这里:transform-decorators-legacy、transform-class-properties。而在.roadhogrc
配置文件中也额外配置了babel
的插件:transform-runtime、dva-hmr、babel-plugin-import。其中唯一需要多说一点的是按需加载插件babel-plugin-import
,它可以针对antd插件中的部分元素样式进行按需加载。
其实不用更多了解相关内容,只需知道如此配置之后,1.开发者可以使用最新的ES6
书写代码;2.放心使用react相关插件;3.在进行run start
或run build
时,代码能够自动转换成ES5
代码,从而在浏览器中执行。
项目中的几个目录
其中mock
是本地模拟数据目录、node_modules
是依赖库目录、public
是入口目录、src
是源码目录、tests
是测试工具目录。在进行npm run build
之后还会生成(默认情况下)dist
目录,这是生成的生产环境下的运行代码目录。其他目录不必多说,只需要核心了解src
的目录组成即可。
├── src
│ ├── common # 应用公用配置,如导航信息
│ ├── components # 业务通用组件
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # dva model
│ ├── routes # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── g2.js # 可视化图形配置
│ ├── polyfill.js # 兼容性垫片
│ ├── theme.js # 主题配置
│ ├── index.js # 应用入口
│ ├── index.less # 全局样式
│ └── router.js # 路由入口
index.js 应用入口
这个页面核心就是import
、const
这两个命令,至于其是否是ES6
的暂且不管。
import
语法介绍见这里。在index.js
这个文件中核心就是加载并执行了一系列module
,并引入了dva
、models
两个变量。
有关ES6的语法推荐查询阮一峰翻译的ECMAScript 6 入门,后续不再赘述。
const
语法介绍见这里。这里就是声明了一个变量app
。
其他
至于index
页面中的const app = dva({})
、models.forEach((m)=>{app.model(m);});
、app.router(require('./router'));
、app.start('#root');
这几句代码暂时不理会,待梳理调用流程时再进行解析。
简单说一下,由于这里是入口,所有这些内容都是用来进行全局设置的,至于其如何实现?如何调用?这些是细节内容,在概略浏览代码时,可以不关注这些点。
router.js 路由入口
这个页面核心就是定义路由策略。并引出了export
命令。
export
语法介绍见这里。这里是将定义好的函数RouterConfig
默认输出出去。
定义路由策略
通过function
关键字定义了RouterConfig
函数,其输入参数是{history}
对象,返回值是一个页面,其由LocaleProvider
、Router
、Switch
、Route
、Redirect
标签(component)组成的。其中每个component从哪里来,怎么操作暂时先不去关注这些细节,在模仿实现的时候可以有样学样。
核心认识到通过/user
路径可以访问到UserLayout
,通过/
可以访问到BasicLayout
,默认情况下(Redirect
),会跳转到/
。具体代码就是如下这段:
<Switch>
<Route path="/user" component={UserLayout} />
<Route path="/" component={BasicLayout} />
<Redirect to="/" />
</Switch>
其他文件
theme.js
主要是主题配置、index.less
主要是进行了全局样式设置、polyfill.js
是兼容性垫片、g2.js
是可视化图形的配置。一般情况下,如果不需要修改全局样式、主题修改、对g2进行配置,不进行额外的浏览器兼容性考虑,这些文件可以不进行深入了解。
其实对这些文件的加载过程是其使用的脚手架完成的,暂且不深入了解脚手架及webpack
相关的实现机制。
dva
先来看看dva
的介绍:dva
是基于现有应用架构 (redux
+ react-router
+ redux-saga
等)的一层轻量封装,没有引入任何新概念,全部代码不到 100 行。dva
是 framework,不是 library,类似 emberjs,会很明确地告诉你每个部件应该怎么写,这对于团队而言,会更可控。另外,除了 react
和 react-dom
是 peerDependencies
以外,dva
封装了所有其他依赖。dva
实现上尽量不创建新语法,而是用依赖库本身的语法,比如 router
的定义还是用 react-router
的 JSX
语法的方式(dynamic config 是性能的考虑层面,之后会支持)。 引用自这里,github的中文介绍在这里
这又引出了一系列新的概念:redux
、react
、react-router
、react-dom
等。暂且先不管这些新的概念是什么,只需要知道dva
是一套框架(framework),尽量不引入新的语法,只是明确了每个部件该怎么写。
redux
由于dva
是一层皮,其内涵是redux
、react
等。那就了解下redux
是什么?redux
的中文文档从这里找到。用几句话概括就是:Redux
是 JavaScript
状态容器,提供可预测化的状态管理。可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。
从阅读其介绍就可以获知:Redux
试图让 state
的变化变得可预测,它就是管理state
的解决方案。至于如何使用redux
、它具有哪些核心概念、如何操作redux
中的函数、使用它有哪些注意事项。可以通过学习redux
获知。这应该是2天工作量的就可以完成的学习任务。
由于后续进行开发时会反复使用到redux
相关的概念,这一章节必须进行扩展学习,可以安排后续的学习任务。但为不影响主线,暂且放下,进行整体思路梳理。
react及其他
React
是一个采用声明式,高效而且灵活的用来构建用户界面的框架。因此,有必要对react
的基础逻辑进行理解,此处需要安排2天的学习任务,了解react
的基础知识。中文的教程在这里
React Router
是完整的 React
路由解决方案。React Router
保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。中文教程在这里
React Dom
提供了针对dom的方法,具体参考这里。
各目录及相互关系
common
是应用公共配置,如导航信息;components
是业务通用组件;layouts
是通用布局;models
是dva model
;routes
是业务页面入口和常用模板;services
是后台接口服务;utils
是工具库;e2e
是集成测试用例。
从入口开始看起,一步步抽丝剥茧看看各个组件之间是怎样进行调用的。
首先在index.js
中加载了models
中的所有model
并进行了注册。其中app.model()
函数来自于dva
的用法,而且model
的概念也是dva
中的概念,详见这里,而所有的model
均来自于./models
目录。之后又通过app.router()
语句注册了路由表,详细介绍见这里。index.js
文件的最后调用了 app.start('#root');
,这句话的含义是启动应用,详细介绍见这里。
在启动应用之后,开发者可以通过浏览器向服务器发起请求访问,以获取页面和数据。不详细展开路由过程,依照路由字面含义。在访问/
时,会被路由到BasicLayout
布局页面(此处参见router.js
)。
布局页面
布局页面在开始的位置import
了一系列的组件(component),定义了一些const
(常量),先不去管它。接下来出现了诡异的class
关键字,这有中java
代码乱入的感觉,没关系。这是ES6
的新特性,参见这里,简单理解起来可以将之看作对象。这个class
继承自React.PureComponent
,在class
中定义了静态变量、构造方法,以及一系列的内部方法,值得注意的是方法只有被调用时才会执行,因此class
中的一系列方法都可以视为声明,而不会顺序执行。直到最后出现了一个render
方法,这个方法会在渲染组件时被调用(此处请参考react组件相关),因此我们关心页面显示相关逻辑就主要是关注render
这个方法。
在对render
方法展开说之前,先把BasicLayout
最后的export
说完。export default
是ES6
相关语法,前面已有介绍,指默认输出。connect
是react-redux
中的一个api,是用来连接 React
组件与 Redux store
的,其用法详情见这里,只需知道其返回的仍是原React
组件(当前事例中是BasicLayout
),并与已有的状态信息state
相关联。
再展开说render
。1.在render
中,用到了一系列来自antd
的组件如:Layout
、Menu
等,其相关的介绍不展开,可以到antd
网站参考其相关教程。2.当然也需要用到dva
封装好的有关路由的一系列组件,如:Link
、Route
、Redirect
、Switch
。3.同样也用到了ant design pro
中创建的组件,如:HeaderSearch
、NoticeIcon
、GlobalFooter
。如果深入进去了解每个组件的实现原理,会不可避免陷入泥潭,对此只需阅读antd
、dva
的相关api,明确该组件是什么、怎么做就好,接下来就是实践中掌握。
BasicLayout
布局的render
中,核心布局就是左边栏(Sider
,参考antd
的Layout.Sider)、顶部(Header
,参考Layout.Header、内容区(Content
,参考Layout.Content。在内容区除了整体的可更换的页面以外还有自创建的脚部区域(GlobalFooter
),其中左边栏、顶部使用了ant design pro
样例中自创建的组件,包括:搜索框(HeaderSearch
)、通知提醒框(NoticeIcon
),以及antd
中已经封装好的通用模板:菜单栏(Menu
)、下拉菜单(Dropdown
)、头像(Avatar
)、加载中(Spin
)、图标(Icon
)、标签(Tag
)、全局提示(message
)。如上所述,有关antd
、dva
中已经封装好的通用模板,应当阅读相关的api,而不应该重新造一遍轮子。
整个布局页面大体就是这个样子,在
ant design pro
中还提供了另一个页面布局就是UserLayout
。如果实际开发中还需要其他的页面布局,就需要自己撰写,大体来说就要研究清楚BasicLayout
页面中的各方面细节,并能够再依照需求完成创建。
Redirect 路由
在BasicLayout
页面布局中,Content
区是通过
{
getRouteData('BasicLayout').map(item =>
(
<Route
exact={item.exact}
key={item.path}
path={item.path}
component={item.component}
/>
)
)
}
<Redirect to="/dashboard/analysis" />
完成页面加载。有关Redirect
、Route
的详细介绍在这里或这里。先来看看getRouteData
函数干了什么。
getRouteData
函数来自于../utils/utils
文件,通过对utils.js
查看,可以看出该函数引用了../common/nav
文件,也就是nav.js
,结合nav.js
文件进行梳理。综合三个位置可以分析得到如下过程:
- 在
nav.js
中通过import...from...
引入了layouts
、routes
中的布局页面和业务页面(常用模板)。由此可知 如需添加新的页面可以参照这个格式引入。 - 在
nav.js
中定义了data
,以json
的格式定义了菜单目录结构,并将引入的页面(1.)以变量的形式引入进来。这个目录内在含义可以后续深入了解,需要注意的是:在添加新页面时应参照这个json格式添加。 - 通过
export default
关键字把data
输出出来。 -
utils.js
中,import navData from '../common/nav';
引入了刚刚定义的data并重命名为navData。 -
utils.js
中的函数getRouteData
中,用到了数组对象中的函数some
(官方中译文档、解读参考)、filter
(官方中译文档、解读参考)以及lodash的cloneDeep
。 - 依照字面意思来理解,
getRouteData
做了两件事:1.对输入参数path
,进行检查,如果检查不通过返回null
(检查含义主要是确保path
是一个有效layout
,同时layout
的children
不为空);2.对检查通过的path
,获取该布局下的所有数据,并将数据转换成数组,数组的每个元素是被称为item
,该item
具有path
属性、exact
属性、component
属性、children
属性。 - 解释下
item
的四个属性:path
属性会赋值给外层调用中Route
的path
属性;component
属性会赋值给外层调用中component
属性;children
属性是用来控制如何进行递归的;exact
属性会赋值给外层调用中exact
属性。 -
getRouteData
就获得了具有path
、component
等属性的元素数组。 - 在
BasicLayout
中调用了getRouteData
函数并对返回数组逐项拆解,组成Route
。 - 通过以上过程就将
nav
中的json
格式配置转换成了页面中的跳转路由。当页面中的地址栏中出现/一级目录/二级目录
时,就可以通过Route
找到对应的component
并进行加载。
这样一来,layouts
、routes
、nav.js
、utils.js
之间进行路由的链路就清晰了。由于我们是在实践中学习,对一些实现细节还不必过度深究,只需要知道页面是怎样串起来的,以及为什么改变nav.js
中的目录样式就能够操作路由,同时能够结合实际的路由需要对路由进行必要整改就可以动手执行了。
Menu 导航菜单
导航菜单顾名思义就是左侧栏中的内容,在BasicLayout
中就是这段代码
<Menu
theme="dark"
mode="inline"
{...menuProps}
onOpenChange={this.handleOpenChange}
selectedKeys={this.getCurrentMenuSelectedKeys()}
style={{ margin: '16px 0', width: '100%' }}
>
{this.getNavMenuItems(this.menus)}
</Menu>
核心函数封装成了getNavMenuItems
,其操作的对象是menus
属性,而在构造方法中对menus
的值进行了初始化。综合来看梳理成如下过程:
- 在
BasicLayout
的构造方法中,通过getNavData
方法获取到nav.js
中定义好的data
。 -
data
本身是数组,通过reduce
(官方中译文档、解读参考)方法和concat(官方中译文档)方法将数组规约成一个新的数组。新的数组是原数组中每个元素的children
数组再拼装在一起组成的。换句话说,nav
中定义的data
,第一层级是布局(layout),布局的children是页面集合(第二层级),页面集合的children是业务页面(第三层级)。此处的转换就是将layout去掉,拼装成页面集合(第二层级)的数组。 - 在
getNavMenuItems
函数中,对menus
进行操作。对每一项(也就是页面集合)转换成一个Menu.Item
。这是可以理解的。 -
getNavMenuItems
函数从上到下核心做了5件事:1.判断有没有可显示的name
,如果没有将返回null
;2.给item
制定path
,也就是跳转路径,采用父子路径拼装的思路完成;3.如果存在children
且存在name
不为空,构造子菜单SubMenu
;4.明确可显示的图标;5.拼装成Menu.Item
- 在拼装
Item
过程中,涉及到了跳转路径path
的构造、可显示的name
、icon
。
结合路由和导航就可以理解整个页面左侧导航栏的动态显示、通过导航栏的点击实现页面的路由过程。
布局页面的其他关注点
在BasicLayout
中还引入了styles
,这是一个less
文件。
Less
是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。
因此只需要把less当成是基本的样式对待就好。虽然它有不少新的特性,但大多数情况下,styles都是出现在某个组件的className
位置,以引用的方式加入进来(css的外联)。
有关Link、Icon等框架提供的组件,需要自行查阅相关API,HeaderSearch
、NoticeIcon
、GlobalFooter
的用法在后续提到components
的用法时再行展开。
动态获取数据
在BasicLayout
页面中进行动态加载数据就涉及到React
的组件生命周期,相关资料也可参考这里,总之在BasicLayout
页面中用到的就是componentDidMount
函数进行数据动态加载的。这个函数核心只是调用了dispatch
:
componentDidMount() {
this.props.dispatch({
type: 'user/fetchCurrent',
});
}
此时就要引出前面提到的dva
、redux
相关的概念了。上文中提到了app.model()
这个函数及其参考。接下来把整体逻辑串起来:
- 通过
app.model()
方法,对model
进行注册,这个model概念来自于dva
。 -
model
中的effects部分,包装自redux-saga
。 -
this.props.dispatch
方法源自redux
,见这里。 - 在
model
注册时,其实就是注册了一系列的监听器,等待着被触发。 - 在
dispatch
时,会接受一个Action
对象作为参数,将它发送出去。关于redux的数据流程参见这里。 - 以
'user/fetchCurrent'
为例,依照dva
的逻辑会找到model
中的user
命名空间,并在其下找到fetchCurrent
方法。因此,dispatch
之后会触发models/user.js
中的fetchCurrent
方法。 - 又通过
import
加载了services/user.js
中的queryCurrent
异步调用方法。 - 在
services/user.js
中,import
了utils/request.js
,并调用了其中的request
请求。并传递请求路径为'/api/currentUser'
- 最终在
utils/request.js
中找到了request
函数,其核心调用了dva
的fetch
函数进行url请求。 -
dva
中的fetch
包装自isomorphic-fetch
,说明见这里。 - 至此将发起
fetch
请求,向服务端请求相应的数据。以queryCurrent
为例,将利用url:'/api/currentUser'
。 - 在
.roadhogrc.mock.js
中配置了代理,同时可以找到/api/currentUser
请求返回的数据。后续不再赘述。
通过上述分析,可见关键点在1.model
的撰写和注册;2.dispatch
的正确调用;3.后台业务请求的封装。这涉及到了models
、services
目录内容及utils/request.js
(由于这个文件主要完成的是底层封装,基本可以不去关注。以添加新的后台请求为例,需要完成:1.在services
目录下定义好请求的url以及函数名称;2.将该后台请求添加到对应的model
中。以添加新的数据加载为例,需要完成:1.在models
目录下中定义新的model
,注意namespace
、state
、effects
、reducers
、subscriptions
的合理使用;2.如果涉及到后台请求数据需要引入services
;3.在合理的事件处发起dispatch
。需要注意的是dispatch
的目录要与model
的namespace
相一致。
components目录
这个目录其实是抽象出来的一系列的业务通用组件。详细内容不再展开。包括BasicLayout
中已经提到的HeaderSearch
、NoticeIcon
、GlobalFooter
组件,实际上都是自行封装的结果。
e2e目录
这个目录是端到端测试的相关目录,相关信息可以从这里了解一些。
由于不在主线学习范围之内暂不理会。
关于redux-auth-wrapper
这个项目的github地址在这里。
通过对这个项目demo的初步体验,感觉到它是基于redux的state进行设计的。先来说说state,这是驻留在浏览器内存中的一个数据结构,可以讲起理解为记录在浏览器(客户端)中的用户最新状态信息。redux-auth-wrapper的作用位置是route时,就是利用state中的信息验证用户是否可以进行跳转。这是对用户体验的一重优化。
有关图标
扩展当前的图标
核心参考这篇扩展教程。
Q:为什么需要用到扩展图标?
A:阿里框架所使用的图标库,不足以满足实际开发需要。
Q:阿里框架库中有哪些图标?
A:阿里框架中的所有图标可以在ant design的资源列表中下载到,点击这里。
Q:为什么在下载的图标库中有些图标找不到?如:dashboard,它出现在ant design pro的项目中,但是在图标库中却没有。
A:因为ant design pro依赖的是ant-design-3.0.0-beta.5,阿里发布的图标库的版本号是2.10.x
Q:如何找到最新的图标库?
A:可以在ant-design代码库的tag中找到3.0.0-beta.5的代码中找到。其路径是components\style\core\iconfont.less中能够找到映射关系。当然阿里使用了一整套的图标(svg、ttf、woff、eot等多种格式,扫盲贴见这里),并用css和js完成适配映射,将图标映射成16进制的unicode,并指定相应的class代码。只要确保工程项目中使用到的图标库中存在某个图标,就可以直接在项目中使用相应的unicode代码或class代码。如果工程项目中使用到了第三方图标,可以对其扩展。
Q:如何依照阿里的icon框架进行图标扩展?
A:参考扩展教程。
Q:还有哪些值得参考的与ant design图标有关的资料?
A:1.图标设计规范;2.本地部署 Iconfont 示例;3.antd图标库2.10.x;4.内网环境使用离线Icon图标资源
Q:在adp项目中应该怎么操作?
A:由于我们的工程打包环境是可以联网的,因此不需要进行离线Icon设置,也不需要完成Iconfont的本地部署。只需要按照扩展教程进行新组建的扩充即可。在扩充时用iconfont添加新的icon,然后构造成相应的图标库,在下载到对应位置即可。鉴于已完成基础性操作,后续添加新图标的流程:1.在iconfont的图标库中添加新的图标;2.将图标库下载下来覆盖项目图标目录
/public/fonts/iconfont
;3.在项目中使用图标代码。
React Developer Tools
Q:react的源代码通过编译组成了普通html、css代码。那怎样在浏览器中查看对应的源代码?
A:使用React Developer Tools可以辅助在chrome中查看源代码,参见这里。
Q:相关链接
A:chrome插件下载地址
有关样式的几个注意事项
Q:如何在ant design的样式代码中使用css常用的'-'?如:“font-size”
A:此处核心遇到的是js中的'.'取值与'[]'取值的区别,参考这里的解答。
Q:ant design中推荐哪种方式编写样式?
A:ant design中推荐使用驼峰式的样式书写,如:'fontSize'。同时这个框架中大量使用了'.'操作符进行对象操作,使用import语法进行整个的代码组织。
Q:在引用样式时传统的写法可以使用多个classname,如
class="csdn-toolbar csdn-toolbar-skin-black "
,在ant design中怎样使用多个样式?A:使用composes,参考这里的
Class 的组合
章节。Q:还有哪些注意事项?
A:1.在ant design的框架下推荐XXX.js文件与XXX.css(或XXX.less)文件放在一起,而不是使用分开的css、html、js目录分别管理不同类型的文件。这是源自react的模块化管理的思想。2.CSS Modules是ant design中默认使用。简要介绍见这里。
Q:为什么样式会变成类似于
class="globalFooter___1cM92"
?A:因为CSS Modules定义了局部作用域的概念,为达到局部作用效果,构建工具会对class的name进行哈希操作,使类名变成独一无二。常用工具就是webpack,而使用的插件是css-loader。
关于数据查询的方法
Q:如何制定模拟的数据请求?
A:ant design pro中使用了mock。可以在.roadhogrc.mock.js中进行数据请求配置。比如
'GET /api/testapi'
是新添加的模拟数据请求。可以尝试在浏览器中访问这个url:http://localhost:8000/api/testapi
,确认该接口可以访问数据。Q:在ant design pro中如何发起数据请求?
A:在services目录中的文件添加一个request请求。如:
export async function queryTestData(){ return request('/api/testapi'); }
就在js中定义了一个request,发起相应的request请求。因此,就可以在需要请求数据的位置直接调用queryTestData
方法。Q:可不可以在页面点击事件中直接调用
queryTestData
方法?ant design pro中为什么没用这种方法?A:首先,这种调用方法是基础的调用,是可以在页面布局中引入相应的文件直接调用这个函数的。ant design pro中遵从了react和redux的设计理念,承认component的模块化设计理念,并加强浏览器缓存的管理。
Q:ant design pro设计框架中在哪里调用
queryTestData
方法?A:在models中进行调用。
Q:那models有什么含义?
A:在浏览器的缓存中,每个component都有其自身的state(这是redux里的基础概念),也就是缓存。而models就是缓存进行对象化管理的抽象。因此可以把models中的model看作是不同的业务对象。而每个业务对象都可以按对象逻辑调用service方法。如在models/user.js中进行如下调用:
*fetchTestData(_, { call, put }){
const response = yield call(queryTestData);
yield put({
type: 'returnTestData',
payload:response,
});
}
Q:fetchTestData函数书写有什么值得注意的地方?
A:1.这个函数写在model中,model的概念来自于dva,见这里,同时其概念解释见这里。2.要充分理解model的概念,才能更合理书写和调用相关函数。3.model的概念还整合了redux-saga的设计理念。4.model中的effects设计来源于redux-saga的设计,参考这里。5.effects部分中使用了星号和yield关键字,是源自于ES6中的Generator语法,以及异步调用,因此只需要认识到星号标识了这不是普通函数,是可以暂停执行的,加星号以示区别;yield标识此处可以暂停,并在获得执行权时从此处开始执行,调用方式参考文档里的next调用。6.call和put来自于redux-saga(是Redux异步操作的中间件),更全的redux接口见这里。7.call实际上就是创建了一条描述结果的信息(上例中的含义就是异步(yield)调用queryTestData,调用完成后(call)将结果赋值给response)。8.put实际上是用来创建dispatch Effect的(上例中的含义就是异步(yield)调用returnTestData,并传递参数response),可从这里、这里以及这里了解更多的信息。
Q:model中如何改变相关状态?
A:model的状态存储在state对象中,在示例中我们添加了
testdata:{},
对象。依照redux的设计理念,所有对状态的修改都应该在reducer中完成。因此model中的reducers部分就是定义一系列修改state的函数,如:queryTestData函数。Q:model中的state和action是什么?
A:其中state是函数调用前的状态,而action就是dispatch发出的action。
Q:model中的状态信息(state)怎么在页面中使用?
A:通过connect函数(来自于react-redux),其实connect设计的初衷就是把容器组件与redux相连接。其更多使用方法见这里。在示例中,就是通过
@connect(state => ({
chart: state.chart,
testdata: state.user.testdata,
}))
方法将redux中的state连接到了这个页面(容器组件)中。通过这句话testdata: state.user.testdata,
就将全局state中命名空间(namespace)为user下的状态(state)属性testdata对象与容器组件中的testdata属性(存在于props中)相关联。
- Q:怎样把容器组件中的属性与页面显示相关联?
- A:通过
const { chart,testdata } = this.props;
这句话能够把属性(props)中的对象testdata解析出来。在页面上通过{testdata.name}
将相应的值取出来。
例:Analysis页面折线图切换
<Card
loading={loading}
className={styles.offlineCard}
bordered={false}
bodyStyle={{ padding: '0 0 32px 0' }}
style={{ marginTop: 32 }}
>
<Tabs
activeKey={activeKey}
onChange={this.handleTabChange}
>
{
offlineData.map(shop => (
<TabPane
tab={<CustomTab data={shop} currentTabKey={activeKey} />}
key={shop.name}
>
<div style={{ padding: '0 24px' }}>
<TimelineChart
data={offlineChartData}
titleMap={{ y1: '客流量', y2: '支付笔数' }}
/>
</div>
</TabPane>)
)
}
</Tabs>
</Card>
- Q:怎样从接口中获取数据?
- A:涉及到数据获取的部分有两个对象:offlineData、offlineChartData。这两个对象都是通过如下方法实现的数据调用,详细过程见'关于数据查询的方法'部分
componentDidMount() {
this.props.dispatch({
type: 'chart/fetch',
}).then(() => this.setState({ loading: false }));
}
Q:
currentTabKey
怎样在页面实现数值传递?A:先明确页面加载时会调用的几个函数:
componentDidMount
、componentWillUnmount
、render
。这涉及到react组件的生命周期概念,参考这里的简介。现在只需要知道:
componentDidMount()
方法会在组件(所谓组件就是Component
)挂在之后调用一次;
componentWillUnmount()
方法会在组件被卸载时调用。;
render()
有四种触发场景,详情不赘述,只需知道页面中调用this.setState
方法是会触发当前组件的更新。
可以看出如下过程:
1.组件初始化时定义了currentTabKey
变量,并赋值为'';
2.在初始化时最后调用了render
方法,依据currentTabKey
给activeKey
进行赋值;
3.在真正渲染时通过activeKey
设置Tabs
的activeKey
属性并传值给CustomTab
组件;
4.在Tabs
组件被点击时通过onChange
方法回调handleTabChange
函数;
5.在回调函数中通过this.setState
将state
中的currentTabKey
值修改;
6.this.setState
触发了render
函数被再次调用。Q:还有哪些是值得关注的点?
A:
TabPane
的变量通过const { TabPane } = Tabs;
从Tabs
中析取出来,也就是说TabPane
是定义在Tabs
中的一个子组件;
CustomTab
是一个自定义组件,由于其在Tab
的页签位置,同时使用了ReactNode
来做页签,因此需要自行控制选中状态,由此theme={(currentKey !== data.name) && 'light'}
和color={(currentKey !== data.name) && '#BDE4FF'}
就是在控制相应的样式。
相关链接整理
很有用的单独说一遍
dva:github项目
React中文文档
React 入门实例教程(阮一峰)
Redux 入门教程(一):基本用法(阮一峰)
Redux 中文文档
Redux-saga 中文文档
Redux 三重境
ECMAScript 6 入门
React Router 中文文档
React Router 使用教程(阮一峰)
Ant Design 指引
全
dva:github项目
dva:React+Redux最佳实践
dva:中文Readme
dva:中文API
一起学react (1) 10分钟 让你dva从入门到精通
初识 Dva
dva源码解析(一)
dva 入门:手把手教你写应用
React中文文档
React:State&生命周期
React:组件 & Props
React 入门实例教程(阮一峰)
React PureComponent源码解析
ReactJS分析之入口函数render
谈一谈创建React Component的几种方式
React Dom
Redux 入门教程(一):基本用法(阮一峰)
Redux 关于react-redux中的connect用法介绍及原理解析
Redux 中文文档
Redux 数据流
Redux-saga 中文文档
Redux-saga 实践总结
Redux 三重境
实例讲解基于 React+Redux 的前端开发流程
ECMAScript 6 入门
ES5中新增的Array方法详细说明
Ecma标准
Lodash 中文文档
exports 和 module.exports 的区别
ES6:export default 和 export 区别
fetch的用法
React 语法之let和const命令
ES6展开运算符
React Router
React Router 中文文档
React Router 使用教程(阮一峰)
React Router Redirect
path-to-regexp
Path-to-RegExp 使用
Ant Design 指引
Ant Design of React
Ant Design Pro教程
自定义主题开发中,修改theme.js需要重启
如何评价 Ant Design 这个项目(一个设计语言)?
Ant Design源码分析(一):Icon组件
roadhog
less 快速入门
Less简介及简单用法
Babel 入门教程(阮一峰,<s>不知何故他已经在自己的博客中删除了,只能从archive找到</s>)
stylelint初体验
JS/React 开发者的 Atom 终极配置
自动化e2e测试 -- WebDriverJS,Jasmine和Protractor
Webpack单元测试,e2e测试
怎么为大中型的vue.js项目编写e2e测试?
Atom编辑器折腾记_(23)加快React开发的插件汇总
Fetch API
react&webpack使用css、less && 安装原则 --- 从根本上解决问题。
less-loader
webpack-中文文档
React中的DOM操作
编辑器配置
js代码检测工具
css代码审查配置
git版本配置
travis持续构建工具配置
roadhog配置
web前端项目配置文件
jest
lint
如何配置 antd theme 的例子
dva-hmr
babel-plugin-import
babel-preset-env
babel-preset-react
transform-decorators-legacy
transform-class-properties
transform-runtime
antd