刚入职一个星期,因为公司的前端框架是用React的,而我以前都是用Vue的,所以又要从头开始学了,听很多人说React上手挺难的,辛亏有Vue的开发经验,看了两天就开始上手公司的项目了,公司主要做的是偏向后台管理系统,所以就采用Ant Design Pro这个框架(蚂蚁金服做的),又是一番挣扎啊。这篇文章就当是对这个星期挣扎的总结吧。
安装
有两种方法:
- 直接克隆它的模板
$ git clone --depth=1 https://github.com/ant-design/ant-design-pro.git my-project
- 通过脚手架安装(
ant-design-pro-cli
)
$ npm install ant-design-pro-cli -g //安装全局的脚手架
$ pro new 项目名字 (my-project) //初始化项目
模板下载下载来了然后要下载它的依赖
$ cd my-project (项目的名字) //进入目录
$ npm i (install的缩写) //安装项目依赖
温馨提示:由于国内原因npm下载依赖会有点慢, 大家可以把npm的源切换到淘宝的镜像源或者用cnpm来安装依赖
切换源(运行下面的命令):
$ npm config set registry http://registry.npm.taobao.org/ //切换淘宝的源
$ npm config set registry https://registry.npmjs.org/ //原来的源
cnpm(运行下面的命令):
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完成,现在开始进入开发模式,嘿嘿!!!
第一步肯定是要看目录啊是吧?(应该是)
看到这么多目录,如果是没有这方面的架构的开发经验,肯定会有无从下手的感觉,所以下面我就把我上手这个框架的一些思路写下(希望这篇文章能让大家少踩点坑嘿嘿)
上手之前最好有以下的知识点: React、Dva、Webpack、ES6、Less等等。
小提示:开始之前先来配置下webpack的alias属性吧,这个是配置路径的别名的
打开根目录下面的.webpackrc
文件
alias: {
components: path.resolve(__dirname, 'src/components/'),
src: path.resolve(__dirname, 'src'),
utils: path.resolve(__dirname, 'utils')
}
//保存之后记得重启下项目喔
然后就可以在项目里面进行愉快的开发了比如:
要引入一个components的组件,不管你在那个目录直接 import * from 'components/对应的组件' 不用在各种../了,是不是很方便。
接下来就是正题了
1.主入口文件index.js:
比较重要的
import './index.less'; //引入全局的样式
// 1. 初始化
const app = dva({
history: createHistory(),
});
// 2. 注册全局的插件
app.use(createLoading());
// 3. 注册全局的模型
app.model(require('./models/global').default);
// 4. 注入路由配置
app.router(require('./router').default);
// 5.启动 #root 是index.ejs 里面的一个根节点id,可以更改
app.start('#root');
2.布局(layout)
And DesigR Pro 提供了3种布局
BlankLayout 这个是空白的布局
UserLayout 这个是登录的界面的布局,如下图:
PageHeaderLayout 这个是后台界面的经典布局,头部导航,左侧固定导航,右边是内容,如下图:
这个我想着重说下怎么新建一个自己想要的布局:
1.首先在src/layout
里面新建一个NewLayout.js
布局,这里说下我要的布局:左侧固定导航,右侧直接根据导航显示对应的页面。
NewLayout.js
import React, { Component } from 'react';
import { Row, Col } from 'antd'
import { Route, Switch } from 'dva/router';
import { getRoutes } from 'src/utils/utils';
export default class NewLayout extends Component {
constructor(props){
super(props)
}
render(){
const { routerData, match } = this.props;
const routes = getRoutes(match.path, routerData);
return (
<Row>
<Col span="4" style={{background: "#000", position: 'fixed',color: '#fff', height: '100%'}}>左侧固定导航</Col>
<Col span="20" offset={4}>
{/* 下面代码的意思是根据路由来渲染对应的组件 */}
<Switch>
{routes.map(item => {
return (<Route
key={item.key}
path={item.path}
exact={item.exact}
component={item.component}
/>);
})}
</Switch>
</Col>
</Row>
)
}
}
然后在根路由中增加这一组新模板src/router.js
function RouterConfig({ history, app }) {
const routerData = getRouterData(app);
const BaseLayout = routerData['/'].component;
const NewLayout = routerData['/new'].component; //新添加的
return (
<LocaleProvider locale={zhCN}>
<ConnectedRouter history={history}>
<Switch>
<Route path="/" render={props => <BaseLayout {...props} />} />
<Route path="/new" render={props => <NewLayout {...props} />} /> //新添加的
</Switch>
</ConnectedRouter>
</LocaleProvider>
);
}
再然后去配置路由src/common/router.js
//只需改routerConfig变量, ['new'] 这个是加载对应的Model,稍后会说。
const routerConfig = {
...
'/new': {
component: dynamicWrapper(app, ['new'], () => import('../layouts/NewLayout'))
},
'/new/a': {
component: dynamicWrapper(app, ['new'], () => import('../routes/new/A'))
},
'/new/b': {
component: dynamicWrapper(app, ['new'], () => import('../routes/new/b'))
}
};
自此,新增一个布局就好了,可以在浏览器访问http://localhost/#/new
就会显示我们新建的布局了,访问http://localhost/#/new/a
右侧的内容就显示a页面的内容了,http://localhost/#/new/b
右侧的内容就显示b页面的内容。
3.模型(Model)
因为我们在上面的路由配置里面使用了new这个model,下面我们就来添加这个model。在src/models/
新建一个new.js
一个model主要有5个参数: namespace:String(命名空间,必须在所有模型中保证唯一)、state:Object(model初始化的数据)、effects:Object(所有的异步操作都在这里操作,这里不能改变state,但是可以获取state)、reducers:Object(所有的同步操作,也是唯一可以改变state的地方,要返回一个Object,会覆盖state)、subscriptions:Object(订阅一个数据源)
new.js
import { getUserList } from '../services/api'
export default {
namespace: 'new',
state: {
userList: {}, //用户列表
count: 0 //计数
},
effects: {
/**
* getConfig
* @param {payload} payload
* @param {call, put, select} param1
* 因为都是异步操作,可以用ES6的Generator或者用ES7的async await
*/
*getConfig({payload}, {call, put, select}){
/**
参数说明:
payload: 传过来的参数
call: 执行一个异步的函数,比如请求服务器的接口,返回一个Promise
put: 执行一个action(操作)
select: 获取state,但是不能更改
*/
// 来,demo走一波
//从服务器获取用户列表的数据
let res = yield call(getUserList, {page: 1});
// 然后更新state的数据,这时候就用到put了
yield put({
type: 'updateUser', //执行自身模块的action不用加命名空间
payload: res //把获取来的列表传过去
});
}
},
reducers: {
/**
* 更新学生的数据
* @param {*} state
* @param {*} action
*/
updateUser(state, action){
// 这里可以用解构的方式来合并state
return {
...state,
...action
};
},
/**
* 更新计数器
*/
increment(state){
return {
...state,
count: state.count+1
}
}
},
subscriptions: {
/**
* 每秒更新state的count
*/
interval() {
return setInterval(()=>{
dispatch({
type: 'increment'
})
}, 1000)
}
},
};
4.路由(router)
路由在新增的页面也说了,这里在补充下路由的配置和组件、model的关联
路由配置src/common/router.js
routerConfig = {
'/': {
component: dynamicWrapper(app, ['new'], () => import('../layouts/NewLayout')),
name: '首页' //这个是额外的参数,如果用了PageHeader这个组件,可以生成面包屑导航
}
}
dynamicWrapper //这个函数接收3个参数,1.挂载的对象 2.路由所需要的model,可以多个,前提你已经在src/models里面新建了对应的模型了,名字和文件名字一样就行 3.路由所需要的组价,我们把页面的组件放到src/routes里面
组件、model的关联
//先配置下路由
routerConfig = {
'/user': {
component: dynamicWrapper(app, ['new'], () => import('../routes/User/List')),
}
}
//再src/routes/User 添加对应的组件 List(列表), 组件代码如下:
import React, { Component } from 'react';
import { connect } from 'dva';
// 使用connect注入到props里面去,中间不能有东西,除非同样是装饰器。
@connect(({new, global}) => ({
userList: new.userList
}))
export default class UserPage extends Component {
constructor(props){
super(props);
console.log(props.userList) //就能获取到new模型里面的值了
//在组件想要更改model里面的值可以这样子玩:
//用了connect会自动在props注入dispatch
props.dispatch({
type: 'new/updateUser', //命名空间 + 要执行的action
payload: {
//要更改的数据
}
})
}
render() {
return (
<div>用户列表</div>
)
}
}
services 和 utils 在这里就不说了,最后在说下,如果用了PageHeaderLayout布局,怎么添加一个新的菜单。
打开src/common/menu.js
//你想插入的配置插入下面的代码结构就行
{
name: '用户管理', //菜单的名字
icon: 'user', //菜单的图标
path: 'user', //在路由配置的路径
children: [ //二级菜单
{
name: '用户列表',
path: 'list',
}
]
}
然后在src/common/router.js
的routerConfig变量里面添加相应的路由配置就行了。
{
...
'/user': {
//user的根路由代码可以和新增布局NewLayout显示右侧内容代码一样,一般都会这样子搞
component: dynamicWrapper(app, ['user'], () => import('../routes/User')),
},
'/user/list': {
component: dynamicWrapper(app, ['user'], () => import('../routes/User/List')),
}
}
就写到这里吧,刚学React一个星期左右,这篇文章写了我两天,总结出一些我踩的一些坑,这篇文章权当是一篇学习React的笔记吧,各位大神有看到不足之处的,可以在评论区留言,感激不尽!!!
(逃~)