搭建项目
使用create-react-app创建一个新的react项目。
npx create-react-app my-app
cd my-app
npm start
如需使用typescript作为动态类型检测,则直接使用以下命令创建项目(笔者默认使用typescript):
npx create-react-app my-app --typescript
如果你想在现有项目添加typescript支持,请参考https://react.docschina.org/docs/static-type-checking.html
安装ant-design-mobile:
npm install ant-design-mobile --save
安装react-router-dom:
npm install react-router-dom --save
安装redux、react-redux、redux-thunk:
npm install redux react-redux redux-thunk --save
配置路由
在src文件夹新建layout、pages两个文件夹。layout文件夹下新建MainLayout.tsx文件,pages下新建Home、Order、My三个文件夹,在三个文件夹内分别新建一个index.tsx文件。
|-src
|-layout
|-MainLayout.tsx
|-pages
|-Home
|-index.tsx
|-Order
|-index.tsx
|-My
|-index.tsx
给pages下面的三个文件夹分别添加如下代码:
import React from 'react';
const Home:React.FC = (props: any) => {
return (
<div>
点餐
</div>
)
};
export default Home;
import React from 'react';
const Order:React.FC = (props: any) => {
return (
<div>
订单
</div>
)
};
export default Order;
import React from 'react';
const My:React.FC = (props: any) => {
return (
<div>
我的
</div>
)
};
export default My;
在MainLayout.tsx中添加如下代码:
import React from 'react';
interface IProps {
history: any;
location: any;
}
interface IState {
collapsed: Boolean;
activeIndex: number;
}
export default class MainLayout extends React.Component<IProps, IState> {
render() {
return (
<div className='main-layout'>
<div className='page-wrapper'>
{this.props.children}
</div>
</div>
);
}
}
在src新建routes文件夹。在routes文件夹内新建两个文件,分别为index.tsx、children.tsx:
|-src
|-routes
|-index.tsx
|-children.tsx
在children.tsx中添加如下代码:
import React from 'react';
import {Route} from "react-router-dom";
import MainLayout from '../layout/MainLayout';
import Home from '../pages/Home/index';
import Order from '../pages/Order/index';
import My from '../pages/My/index';
export const ChildRouter = (props: any) => (
<MainLayout {...props}>
<Route exact path="/" component={Home}/>
<Route exact path="/index" component={Home}/>
<Route path="/index/home" component={Home}/>
<Route path="/index/order" component={Order}/>
<Route path="/index/my" component={My}/>
</MainLayout>
);
在index.tsx中添加如下代码:
import React from 'react';
import {HashRouter, Route, Switch} from "react-router-dom";
import {ChildRouter} from './children';
const BasicRouter = () => (
<HashRouter>
<Switch>
<Route exact path="/" component={ChildRouter}/>
<Route path="/index" component={ChildRouter} />
</Switch>
</HashRouter>
);
export default BasicRouter;
在App.tsx中,作如下改动:
import React from 'react';
import 'antd/dist/antd.css';
import './App.scss';
import BasicRouter from './route';
function App() {
return (
<BasicRouter/>
);
}
export default App;
至此,一个嵌套路由就配置好了,在浏览器中输入localhost:3000/#/看看会出现什么。
编写Tabs组件
在src下新建components文件夹及Tabs文件夹,Tabs文件夹下再新建index.tsx、index.scss:
|-src
|-components
|-index.tsx
|-index.scss
在index.tsx中编写如下代码:
import React from 'react';
import './index.scss';
interface IProps {
onTabChange: Function;
activeIndex: number;
tabList: any[];
}
const Tabs: React.FC<IProps> = (props) => {
return (
<div className='tabs-wrap'>
{
props.tabList.map(item => (
<div
key={item.key}
className={props.activeIndex === item.key ? 'tabs-item active' : 'tabs-item'}
onClick={() => {
props.onTabChange(item.key);
}}
>
<i className={`tabs-icon ${item.icon}`}></i>
<br/>
{item.text}
</div>
))
}
</div>
)
};
export default Tabs;
编写样式:
.tabs-wrap {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
bottom: 0;
width: 100%;
height: 50px;
border-top: 1px solid #e0e0e0;
.tabs-item {
flex: 1;
text-align: center;
font-size: 12px;
color: #8a8a8a;
&.active {
color: #1296db;
.tabs-icon.home {
background: url("../../assets/home1.png") center no-repeat;
background-size: contain;
}
.tabs-icon.order {
background: url("../../assets/order1.png") center no-repeat;
background-size: contain;
}
.tabs-icon.my {
background: url("../../assets/my1.png") center no-repeat;
background-size: contain;
}
}
.tabs-icon {
display: inline-block;
width: 25px;
height: 25px;
margin-bottom: 4px;
}
.tabs-icon.home {
background: url("../../assets/home.png") center no-repeat;
background-size: contain;
}
.tabs-icon.order {
background: url("../../assets/order.png") center no-repeat;
background-size: contain;
}
.tabs-icon.my {
background: url("../../assets/my.png") center no-repeat;
background-size: contain;
}
}
}
图标请到iconfont或GitHub仓库自行下载。
然后修改MainLayout.tsx:
import React from 'react';
import './MainLayout.scss';
import Tabs from '../components/Tabs/index';
interface IProps {
history: any;
location: any;
}
interface IState {
collapsed: Boolean;
activeIndex: number;
}
export default class MainLayout extends React.Component<IProps, IState> {
state: IState = {
collapsed: false,
activeIndex: 0,
};
tabList: any[] = [
{
key: 0,
text: '点餐',
icon: 'home',
},
{
key: 1,
text: '订单',
icon: 'order',
},
{
key: 2,
text: '我的',
icon: 'my',
},
];
componentDidMount(): void {
const {location} = this.props;
let activeIndex = 0;
switch (location.pathname) {
case '/':
activeIndex = 0;
break;
case '/index/order':
activeIndex = 1;
break;
case '/index/my':
activeIndex = 2;
break;
default:
break;
}
this.setState({activeIndex});
}
toggle = (): void => {
this.setState({
collapsed: !this.state.collapsed,
});
};
handleChange = (index: number): void => {
const {history} = this.props;
let url = '/';
switch (index) {
case 0:
url = '/';
break;
case 1:
url = '/index/order';
break;
case 2:
url = '/index/my';
break;
default:
break;
}
this.setState({
activeIndex: index,
});
history.replace(url);
};
render() {
const {activeIndex} = this.state;
return (
<div className='main-layout'>
<div className='page-wrapper'>
{this.props.children}
</div>
<Tabs onTabChange={this.handleChange} activeIndex={activeIndex} tabList={this.tabList}/>
</div>
);
}
}
打开浏览器查看效果
至此,一个Tabs组件的开发完成。