该项目主要是针对 ant-design 配合 react、react-redux、react-router-dom4.0 以及第三方插件BMap、Echarts、Easy-mock来实现的基础应用。
Imooc React全家桶+AntD共享单车后台管理系统开发
- components
- BaseForm //表单封装
- BaseTable //表格封装
- MenuList //路由列表
- PublicFooter //公共页脚
- PublicHeader //公共页头
- config
- constant //常量定义
- menuConfig //映射的路由列表[可由后台返回]
- theme //ant-design主题色更换
- layout
- BasicLayout //基础布局
- PublicLayout //公共布局
- pages
- ui // 存入 ant-design 一些UI组件
- form // antd 表单基础使用
- table // 写入简单表格以及复杂表格的示例
- city // 初次编写查询列表结构
- order // 编写可复用组件查询组件、表格组件
- user // 复用模式完成 查询、功能、列表
- map // 使用BMap创建地点、线路、区域
- charts //使用echarts创建 bar、pie、line
- rich //使用富文本编辑器,并且转换为html输出
- permission //权限设置 用户-角色-权限
- login //登录页面预备
- home //首页,使用两用样式方式sass、less
- reouter-dom //react-router-dom demo
- redux
- action
- reducer
- index.js
- services
- city //城市管理接口
- order //订单管理接口
- styles
- common //公共样式,布局样式
- default //antd默认样式
- loading //全局loading动效
- utils
- filter //常量过滤
- request //请求封装
- utils //公共方法
yarn add antd --save
yarn add moment --save
yarn add axios --save
yarn add echarts-for-react echarts --save
yarn add react-draft-wysiwyg draftjs-to-html --save
yarn add react-router-dom --save
yarn add node-sass sass-loader --save
yarn add less less-loader --save
yarn add babel-plugin-import --save
yarn add jsonp --save
yarn add redux react-redux --save
yarn add redux-devtools-extension --save
由于 create-react-app 初始化项目依赖全部安装在 dependencies,你可能会想 dependencies 是生产环境,devdependencies 是开发环境,脚手架怎么没有区分呢,在这里不做过多的解释,github上面有相关issues。这里我们手动区分安装依赖,初始化安装的依赖,我们放在开发环境中devdependencies,后续学习使用的包,我们安装在生产环境dependencies,仅做与区分。
该项目使用 Easy-mock 模拟前端数据,由于mock数据服务器不稳定,所以把请求内容存放在public/api/目录下,请求添加isMock来区分是否使用mock数据。如果不使用mock数据,请求本地数据,已经在request方法内增加优化 options.isMock?options.url:options.url+'.json'
- 全部引入、按需引入
- 设置主题色
- 使用 echarts-for-react 应用 echarts
-
用户、角色的概念
- 用户:用户是指系统的登录用户,可以理解为一系列的人员,例如张三、李四
- 角色:用户登录系统划分角色,根据角色划分对应的权限
-
权限模型
- 传统的权限模型:用户到权限,登录系统自动获取当前登录人的权限,没有角色的概念
- RBAC权限模型:某个人划分到指定角色,权限/菜单是跟着角色走的,用户被分配某个角色,某个角色拥有某个权限
-
permission Tree question
两种方式渲染树结构,一种是后台返回所有的树结构,另一种方式前端自定义好数据渲染,该项目使用本地定义列表。
-
使用sass或者less create-react-app构建项目应用使用sass方法 首先需要安装node-sass sass-loader 从新启动项目就可以使用sass文件了 首先需要安装 less less-loader 配置对应的文件config/webpack.config.js,具体查看commit提交记录e0b1a8
-
按需加载antd样式
修改less文件两种方式一种是在eject之前使用官方推荐的方式,使用的是官方推荐的 高级配置、babel-plugin-import 使用插件去修改 另外一种方式是在npm run eject 之后修改配置文件,社区自行探索。安装 babel-plugin-import 修改 webpack.config 配置文件,详情见内注解commit记录a5e0fb
-
使用redux需求描述:为完成头部组件面包屑处 展示对应菜单名称
-
需求分析:
1.菜单使用 ant-design Menu 组件渲染,查看相关Api得知,点击 MenuItem 调用函数 function({ item, key })
可以获取当前点击的菜单自定义title以及key的信息。
2.在每次点击 MenuItem 的时候发送 dispatch 修改 state menuName 的值。
3.在头部组件内接收 redux state menuName 的值渲染到面包屑的位置。
- 具体执行步骤:
1.下载 redux react-redux 相关依赖
2.创建redux相关文件
./src
redux
action
index.js
reducer
index.js
index.js
具体内容查看如上文件,主要流程如下,入口为src/redux/index.js
// redux/action/index.js
const type ={
SWITCH_MENU : 'SWITCH_MENU'
}
function switchMenu(menuName){
return {
type:type.SWITCH_MENU,
menuName
}
}
// redux/reducer/index.js
const reducer = (state,action) => {
switch(action.type){
case type.SWITCH_MENU:
return {
...state,
menuName: action.menuName
};
default:
return { ...state }
}
}
// redux/index.js
import {createStore} from 'react-redux'
const initialState = {
menuName:''
}
const configStore = () => createStore(reducer,initialState)
3.使用Provider容器包裹组件,并且传入全局store 文件存放/src/index.js
import {Provider} from 'react-redux'
import configStore from './redux/index.js'
const store = configStore();
<Provider store={store}>
<Router />
</Provider>
4.使用connect连接redux与组件,在组件内发送dispatch
class MenuList extends Component {}
export default connect()(MenuList)
handleClick = ({item,key}) => {
const {dispatch} = this.props;
dispatch(switchMenu(item.props.title));
}
5.使用connect连接redux与组件,在组件内接收state的值
class PublicHeader extends Component {
render() {
// 重点部分,使用connect并添加mapStateToProps使redux state 转换为
console.log(this.props.menuName)
return (<div>内容部分</div>)
}
}
const mapStateToProps = state => {
return {
menuName: state.menuName
}
}
export default connect(mapStateToProps)(PublicHeader)
version v1.0.0 该版本主要使用 antd 基础组件搭建页面、使用按需加载antd、系统同时使用sass/less语法、提取常量、封装公用组件、以及百度地图、Echarts图表应用、设计权限、接入 react-redux 等功能
由于 create-react-app 已经为我们添加了eslint规则,所以eslint一些基本依赖就不需要重新下载了。
手动配置eslint步骤如下:
- 1.根目录下生成eslint配置文件.eslintrc、生成eslint忽略文件.eslintignore
- 2.安装使用相关依赖
yarn add eslint-config-airbnb -S
yarn add eslint-plugin-compat -S
- 3.修改package.json添加启动指令
"lint": "eslint --fix --ext .js --ext .jsx src/",
Eslint配置详解EslintConfig
.eslintrc被设计为完全可配置的,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和匹配 ESLint 默认绑定的规则和你的自定义规则,以让 ESLint 更适合你的项目。有两种主要的方式来配置 ESLint:
- 1.Configuration Comments - 使用 JavaScript 注释把配置信息直接嵌入到一个代码源文件中。
- 2.Configuration Files - 使用 JavaScript、JSON 或者 YAML 文件为整个目录(处理你的主目录)和它的子目录指定配置信息。可以配置一个独立的 .eslintrc.* 文件,或者直接在 package.json 文件里的 eslintConfig 字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在命令行运行时指定一个任意的配置文件。
"parserOptions": {
"desc": "- 这是个对象,表示你想使用的额外的语言特性",
"ecmaFeatures": {
"desc": "启用实验性的语法",
"experimentalObjectRestSpread": true,
"legacyDecotators": true
}
}
"desc": "一个对Babel解析器的包装,使其能够与 ESLint 兼容。",
"parser": "babel-eslint"
ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一
- "off" 或 0 - 关闭规则
- "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
- "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
A mighty, modern linter that helps you avoid errors and enforce conventions in your styles.
手动配置stylelint步骤如下:
- 1.根目录下生成stylelint配置文件.stylelintrc
- 2.install depend
yarn add stylelint -S
yarn add stylelint-config-css-modules -S
yarn add stylelint-config-prettier -S
yarn add stylelint-config-standard -S
yarn add stylelint-scss" -S
- 修改package.json文件,添加启动指令
"stylelint": "stylelint --fix src/**/*.less",
Stylelint配置详情StylelintConfig
.stylelintrc The linter expects a configuration object. You can either craft your own config or extend an existing one.
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier", "stylelint-config-css-modules"]
}
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier", "stylelint-config-css-modules"],
"plugins": [
"stylelint-scss"
],
}
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier", "stylelint-config-css-modules"],
"plugins": [
"stylelint-scss"
],
"rules": {
"indentation": "tab",
"number-leading-zero": null
}
}
stylelint国内翻译的文档较少,使用方式与eslint相似
Prettier is an opinionated code formatter with support
手动配置prettier步骤如下:
- 1.根目录下生成prettier配置文件.prettierrc
- 2.安装使用相关依赖
yarn add prettier -S
yarn add prettier-eslint -S
yarn add prettier-eslint-cli -S
yarn add eslint-plugin-prettier -S
yarn add eslint-config-prettier -S
- 3.修改package.json添加启动指令
"format": "prettier-eslint --write src/**/*.{js,less}",
Prettier配置详解PrettierConfig
.prettierrc Prettier ships with a handful of customizable format options, usable in both the CLI and API.
前面我们已经实现eslint、stylelint、prettier提高代码质量,操作npm run lint/stylelint/format 格式化代码片段,这样可以很好的提高代码质量,但是每次操作都需要手动执行。
这时候我们设想在代码提交的时候格式化代码,如果有什么问题给出对象警告。
配置步骤如下:
- 1.安装使用相关依赖
yarn add husky -S
yarn add lint-staged -S
- 2.修改package.json添加启动指令
"precommit": "lint-staged"
"lint-staged": {
"**/*.{js,jsx,scss,json,less}": [
"prettier-eslint --write",
"git add"
],
"**/*.{js,jsx}": "eslint --ext .js",
"**/*.{scss}": "stylelint --syntax scss",
"**/*.{less}": "stylelint --syntax less"
}
每次提交代码的时候都会执行eslint/stylelint/prettier校验代码,能自动修复的自动修复,不能修复的在控制台给出对应警告。
我们做一个测试,在src/demo/index.js新建一个组件,并且写入不规则代码,首次提交commit 这时候提交控制台会出现对应警告,第二次提交会消除一些可以自动修复的警告,但是还会出现如下报错,报错信息如下:
error Delete `··` prettier/prettier
就因为这个报错信息,导致我挣扎了很久都没把这个部分代码提交,最后我发现是因为.eslintrc里面配置了prettier导致的。
"extends": ["plugin:prettier/recommended"],
这个时候我猜肯定是eslint与preitter功能冲突了,当我查询了很多文档,以及国内外的github,焦头烂额的时候,我发现Webstorm编辑上面也会报错,缩进处标记这着红色波浪线,鼠标放在上面的时候报错信息与上面一致。我就在想是缩进出现的问题。
这个时候冒着试试的方式在根目录下添加.editorconfig配置文件,修改缩进为4。这个时候再次commit可以了,报错信息也没有了。
就在我准备这个报错信息在README记录的时候,我突然在想,既然是缩进导致的,eslint我设置的是4,那我的看看.prettierrc设置的是几,配置文件内没有配置,那我就去官方去看看默认配置的是几PrettierConfig,结果查看 tabWidth
默认是2。
这时候我赶紧把根目录下面的.editorconfig配置文件删除,在.prettierrc配置 "tabWidth": 4
代码回撤,重新commit 这时候也没有报错,提交成功。
nice~ 这个报错终于解决了,并且也找到了相应的解决方案。我觉得应该把.prettierrc配置上并且根目录下也配置editorconfig。这样报错信息解决了,另一方面也能保证大家协同开发了。
switch nav run animate
yarn add react-transition-group -S
切换导航更换内容区动画暂不添加
为 create-react-app 添加最新提案语法支持 decorators 装饰器
- 1.安装依赖
yarn add @babel/plugin-proposal-decorators -S
- 2.修改config/webpack.config.js配置文件
[
require.resolve('@babel/plugin-proposal-decorators'),
{
legacy: true
}
]
- 3.重新启动项目使用@装饰器
具体使用内容见src/pages/home/index.js
为 create-react-app 添加最新提案语法支持 Optional-chaining 链判断运算符
- 1.安装依赖
yarn add @babel/plugin-proposal-optional-chaining -S
- 2.修改config/webpack.config.js配置文件
[require.resolve('@babel/plugin-proposal-optional-chaining')]
- 3.重新启动项目使用链判断运算符 具体使用内容见src/pages/home/index.js
version v1.1.0 该版本主要针对业务代码的格式化、规范化操作,添加 Eslint、Stylelint、Prettier 等检查工具。设置代码提交 commit 之后自动检测代码是否规范,自动修正可预测问题,手动修复console警告。另外还使用 @babel/plugin 等插件,使用 ECMAScript 提案性语法。
使用 create-react-app 创建项目接入 react-redux 把各个页面的数据源存入 redux ,这样对应每个页面都产生一个 store/ 包括acrions、reducer、state,这样来开发一个大项目不以利于后期的维护,取而代之react-redux 为 dvajs,dva是在redux基础上的一层封装,广泛应用于阿里、蚂蚁金服。
本项目只针对 react-redux 实现了一个简单的面包屑功能,如果想了解 react-redux 使用方法请查看 xxxxx
v1.3.0 版本计划对 create-react-app 进行 dva 的接入,接入流程查看 Useing dvajs,并且添加国家语言切换功能
项目已经配置切换为 dva 来控制 store 数据源了,接下来我们要使用 store 给项目添加国际化多语言,我首先简单介绍下国际化和store数据结构的设计:
此处采用 immutable 数据格式,把数据存于 model,同样国际化的判断参数定为: i18n 存于app的model中,取值来源于浏览器的本地缓存localStorage用户若设置了某种语言,则存在这里,用户下次访问系统,也依然能唤起上次所选中的语言,当初次访问时,语言默认先取自浏览器,若依然取不到则默认咱们的中文。
这里我们只实现 中文,英文,繁体 三种语言的国家化即可,因为引用了antd组件库,故此处国际化部分包括两部分,
-
(1)antd库的国际化,比如antd中的固定组件里的 ‘确定,OK’‘下一页,Next Page’等,antd官网有详细说明
-
(2)业务框架自己的国际化,比如“用户名,Username”,“密码,Password”等,这里采用react-intl国际化组件实现
yarn add immutable react-intl -S
npm install immutable react-intl -S
这里我简单介绍下,react-intl是一个国际化的第三方库,目前最新版本为3.3.2,我们切换为2.X的版本来使用该教程
修改models目录下的app.js中引入import {Map} from 'immutable' 如下
import {Map} from 'immutable';
const initState = Map({
i18n: 'zh_CN'
})
export default {
namespace: 'app',
state:initState,
subscriptions: {},
effects: {
* changeLang ({payload: {value}}, { put }) {
yield put({ type: 'updateLang', payload: {value}});
}
},
reducers: {
updateLang (state,{payload:{value}}) {
return state.set('i18n',value);
},
}
};
修改routers目录下BBB.js如下(在页面添加切换语言功能,并且触发dispatch修改state数据)
import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button} from 'antd'
const MenuItem = Menu.Item;
class BBB extends Component {
changeLang=(e)=>{
const {dispatch} = this.props;
dispatch({
type:'app/changeLang',
payload:{
value:e.key
}
})
}
render() {
const {i18n} = this.props;
const menu=(
<Menu
onClick={this.changeLang}
selectedKeys={[i18n]}
>
<MenuItem key="zh_CN">中文</MenuItem>
<MenuItem key="en_US">英文</MenuItem>
<MenuItem key="zh_HK">繁体</MenuItem>
</Menu>
)
return (
<div>
<p>
BBB页
</p>
<Link to={'/aaa'}>去AAA页面</Link>
<br />
<Link to={'/ccc'}>去CCC页面</Link>
<Row>
<Col offset={2}>
<Dropdown trigger={['click']} overlay={menu}>
<Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
</Dropdown>
</Col>
</Row>
</div>
);
}
}
export default connect(({
app
})=>({
i18n:app.get('i18n')
}))(BBB)
上修改主要功能:
app.js 增加初始语言参数i18n,增加effects和reducers方法,用于接收语言切换的action,并存储选中的key值
BBB.js 增加connect使当前组件接入store数据,增加切换组件,用于点击切换语言,并dispatch一个action给app/changeLang,触发修改修改model数据。
到这里,数据层面的流程已经打通,接下来处理国际化逻辑,国际化组件必然放于跟组件或最外层组件包裹,这样全局均可以使用并生效
在src目录下,新建locale组件,Locale组件为国际化报错组件,外层为antd组件、内层为业务文案国际化解决方案,并且根据store的变化来切换语言的使用 locale
在src目录下,新建locales目录,里面新建index.js文件,此目录用于存放所有项目的文案国际化文件 locales
修改src/routers.js文件,使用包裹组件对需要进行国际化的内容进行包裹 routers
修改BBB组件,增加injectIntl国际化的接入,并增加三个示例,两个antd组件 分页和日期,一个业务文案 用户名和密码 BBB组件