theme: channing-cyan
完成底部导航、登陆注册实现
前言
上一章节,从 0 开始搭建出一套以 React
技术栈为基础的前端开发环境,过程中肯定会遇到各奇怪怪的问题,比如 Node
版本问题,工具包的版本问题,插件下载完之后,无法得到自己想要的效果等等,这也是很正常的,所以得耐心百度啊,留言问我也行的。
倘若学会了这一套搭建流程,根据项目需求,灵活的切换组件库、PC 版、甚至是主框架。这对提升自己的知识广度很有帮助,因为相比每次都看教程,自己手动实现一遍,印象会更深刻,遇到问题也能通过自己的认知,去解决它。
话不多说,直接开肝。
知识点
- 编写底部导航栏
- 创建图标公用组件
- 路由控制底部导航栏的显隐
- 组件:
Cell
、Input
、Button
、CheckBox
。
一.编写底部导航栏
先观察今天要实现的底部导航长啥样,如下所示:
上图红框中的底部导航栏,在很多业务场景下都是需要的,三个导航栏对应着三个不同的三个页面组件,分别是「账单」、「统计」、「我的」。这三个页面组件是需要导航栏的。如果点击内页如账单详情页,则底部的导航栏会被隐藏,这就需要在导航栏的控制上,下一些功夫。
话不多说,在上一章基础上添加导航栏组件,在 src
目录下新建 components
目录,专门用于放置一些公用组件,再在 components
目录下新建 NavBar
目录,用于编写底部导航栏,代码如下所示:
Nav/index.jsx
```jsx import React, { useState } from 'react'; import PropTypes from 'prop-types' import { TabBar } from 'zarm'; import { useHistory } from 'react-router-dom'; import s from './style.module.less';
const NavBar = ({ showNav }) => { const [activeKey, setActiveKey] = useState('/'); const history = useHistory()
const changeTab = (path) => {
setActiveKey(path)
history.push(path)
}
return (
<TabBar visible={showNav} className={s.tab} activeKey={activeKey} onChange={changeTab}>
<TabBar.Item
itemKey="/"
title="账单"
/>
<TabBar.Item
itemKey="/data"
title="统计"
/>
<TabBar.Item
itemKey="/user"
title="我的"
/>
</TabBar>
);
};
NavBar.propTypes = { showNav: PropTypes.bool }
export default NavBar; ```
代码解析:
首先是声明 NavBar
函数组件,它接收一个外部传入的 showNav
属性,用于控制导航栏的显示隐藏。
通过 useHistory
钩子方法,拿到路由实例 history
,它内部含有很多路由的方法,在上述代码中,使用到的是 history.push
进行路由跳转。
在页面中,引入 TabBar
组件,它接受几个属性:
- visible:用于控制导航栏的显示隐藏。
- activeKey:当前被点击的导航栏。
- onChange:点击导航栏之后的回调方法,
path
参数为TabBar.Item
的itemKey
属性。
TabBar 官方文档: https://zarm.gitee.io/#/components/tab-bar
所以当你点击导航栏的时候,changeTab
方法便会被触发,执行内部的 setActiveKey
和 history.push
,他们的作用分别是设置当前点击的高亮和让页面跳转到对应的页面组件。
说到跳转到对应的组件,'/'、'/data'、'/user' 这三个路由对应的三个组件还未编写,这里在 pages
目录下新建这三个页面组件,作为占位。
```jsx // Home/index.jsx import React from 'react'
const Home = () => { return
export default Home
// Data/index.jsx import React from 'react'
const Data = () => { return
export default Data
// User/index.jsx import React from 'react'
const User = () => { return
export default User ```
别忘了,前往 router/index.js
添加路由配置,如果不添加这个配置,调用 history.push
这个方法,就无法匹配到对应的页面组件,代码如下: ```js // router/index.js import Home from '@/pages/Home' import Data from '@/pages/Data' import User from '@/pages/User'
const routes = [ { path: "/", component: Home }, { path: "/data", component: Data }, { path: "/user", component: User } ];
export default routes ```
这时,还缺少一步,将导航栏组件引入 App.jsx
入口页面,如下所示:
jsx // App.jsx ... import NavBar from '@/components/NavBar'; ... function App() { return <Router> <ConfigProvider primaryColor={'#007fff'}> <Switch> { routes.map(route => <Route exact key={route.path} path={route.path}> <route.component /> </Route>) } </Switch> </ConfigProvider> <NavBar showNav={true} /> </Router> }
通过 npm run dev
启动项目,浏览器展示效果如下所示:
上图效果所示,注意地址栏的变化,点击相应的 Tab
,调用的 history.push
方法,将地址栏的 pathname
改变,随之而来的是页面组件的改变。这个就应证了之前解释的单页面路由控制的原理。history.push
做的事情就是改变地址栏,地址栏一旦改变,就会触发地址所对应的组件渲染,如 /data
,渲染的就是 Data
页面组件。
你会问为什么导航栏会一直显示在底部,来分析以下代码:
红色框是组件展示的区域,每个路径对应着一个组件,这个在 router/index.js
文件中也有所体现。
绿色框则代表导航栏的位置,也就是说,无论上面的组件怎么变化,底部的导航栏一直都是存在的。
二.添加底部导航图标
将图标写成公共组件,这样便于后面各个页面方便引入,新建 components/CustomIcon/index.jsx
,添加如下代码: ```js import { Icon } from 'zarm';
export default Icon.createFromIconfont('//at.alicdn.com/t/font2236655w1mpqp7n1ni.js'); ```
上述代码,引入 Icon
,执行它的自定义图标方法 createFromIconfont
,它接收一个参数,为 iconfont
生产的静态脚本路径,你可以自己去 官网 配置,也可以直接用我提供的:
里我已经为大家添加好了各个图标,地址就是上述代码的地址。
接着将其引入到代码中使用,打开 components/NavBar/index.jsx
,添加如下属性:
jsx import CustomIcon from '../CustomIcon'; ... <TabBar.Item itemKey="/" title="账单" icon={<CustomIcon type="zhangdan" />} /> <TabBar.Item itemKey="/data" title="统计" icon={<CustomIcon type="tongji" />} /> <TabBar.Item itemKey="/user" title="我的" icon={<CustomIcon type="wode" />} />
查看浏览器展示效果如下:
三.底部导航栏的显示隐藏
在之前引入 NavBar
的代码中,将 showNav
属性写死为 true
。此时,需要将其盘活,打开 App.jsx
,添加如下代码: ```jsx import React, { useEffect, useState } from 'react' import { BrowserRouter as Router, Switch, Route, useLocation } from "react-router-dom"
import NavBar from '@/components/NavBar';
import { ConfigProvider } from 'zarm'
import routes from '@/router' function App() { const location = useLocation() // 拿到 location 实例 const { pathname } = location // 获取当前路径 const needNav = ['/', '/data', '/user'] // 需要底部导航栏的路径 const [showNav, setShowNav] = useState(false) // 是否展示 Nav useEffect(() => { setShowNav(needNav.includes(pathname)) }, [pathname]) // [] 内的参数若是变化,便会执行上述回调函数= return { routes.map(route => ) } }
export default App ```
当你刷新浏览器,控制台应该会报下面的错误:
执行 useLocation
时,报错 location of undefined
。这是因为想要在函数组件内执行 useLocation
,该组件必须被 Router
高阶组件包裹,做如下改动,将 App.jsx
的 Router
组件,前移到 main.jsx
内,如下:
逻辑分析:
拿到 pathname
,将其设置为 useEffect
钩子函数的第二个参数,监听它的变化,一旦 pathname
变化,便会触发回调函数执行 setShowNav(needNav.includes(pathname))
,结果会传递给 NavBar
组件,从而控制组件的显示隐藏。needNav
为需要底部导航的路径值。
不妨做个测试,在 pages
目录下新建一个测试页面组件 Detail
,并且添加路由配置。
别忘记把组件属性修改成动态变量: js <NavBar showNav={showNav} />
查看浏览器就没问题了。
实现了底部导航栏,并且创建了三个主页面,这三个页面是需要展示底部导航栏,现在来制作的「登录注册页面」便是不需要底部导航栏的单独页面。
四.注册页面
系统是面向多用户的,换句话说也就是一个纯正的 C 端项目,任何人都可以通过网站,注册一个新的账号。接下来开始注册页面的编写。
首先新建 Login
文件夹,在文件夹内添加两个文件 index.jsx
和 style.module.less
,先把注册页面的静态页面切出来,首先给 index.jsx
添加如下代码: ```jsx import React from 'react'
import s from './style.module.less'
const Login = () => { return
export default Login ```
为它添加一个路由配置,打开 router/index.js
添加如下: jsx import Login from '@/pages/Login' ... { path: "/login", component: Login }
重启项目,如下所示代表登录注册页面创建成功了:
接下来为 Login/index.jsx
添加静态页面代码:
```jsx import React from 'react' import { Cell, Input, Button, Checkbox } from 'zarm' import CustomIcon from '@/components/CustomIcon'
import s from './style.module.less'
const Login = () => { return