博客管理系统开发 -- 顶部导航栏开发
目录
这一节我将带领大家,来开发博客管理系统的顶部导航功能,其效果最终如下:
一、路由优化
上一节我们介绍了routes的目录结构,其中我们创建了一web.js文件,用来保存路由配置。
/**
* web路由配置项
* @author zy
* @date 2020/4/5
*/
export default {
path: '/',
name: 'home',
component: Home,
exact: false,
childRoutes: [
{path: 'about', component: About},
{path: '*', component: PageNotFound}
]
}
我们每添加一个路由,都需要在这里配置一次,如果路由较多,且存在多层父子关系的情况下,该配置会越来越复杂且结构不够清晰,此外多个人同时开发,每个人都可能去配置路由信息,那样我们就需要解决代码冲突问题。
那么有没有一种简单的方式,我们可以根据views文件夹结构动态生成路由配置信息,当然可以了,我们现在就来介绍。
1.1 views目录创建
我们的博客管理系统设计主要参考了郭大大这位博主的文章:
首先来看一下我们博客系统的主页,我们可以看到导航栏主要包含首页、归档、分类、关于这几个菜单,每个菜单项都对应着一个路由。
因此,我们在views文件夹下创建个web文件夹,并在该文件夹下创建与这几个对应的文件夹,用于保存每个页面对应的视图组件。最终我们views目录结构如下:
其中menu_config.js用于导出菜单配置,我们后面会根据该配置动态生成路由配置信息以及菜单配置信息。
我们首先来看一些about文件夹:
about.jsx:
import React from 'react';
function About(props) {
console.log('About=>', props);
return <h2>About</h2>;
}
export default About;
menu_config.js:
import {UserOutlined} from '@ant-design/icons';
import About from './about';
export default {
title: '关于',
icon: UserOutlined,
path: 'about',
component: About
}
path:指定About组件的路由,由于每个路由实际上都对应这一个菜单项,因此我们通过icon指定菜单图标,title指定菜单名称。
如果一个菜单还有子菜单,比如归档菜单下面还有子菜单github:
archives文件夹下menu_config.js:
import {FolderOutlined} from '@ant-design/icons';
import github from './github/menu_config';
export default {
title: '归档',
icon: FolderOutlined,
path: 'archives',
subMenus: [github]
}
这里我们配置了归档的子菜单github;
github.jsx:
import React from 'react';
function Github(props) {
console.log('Github=>', props);
return <h2>github</h2>;
}
export default Github;
menu_config.js:
import {GithubOutlined} from '@ant-design/icons';
import Github from './github';
export default {
title: 'github',
icon: GithubOutlined,
path: 'github',
component: Github
}
home和categories文件夹同上,就不一一介绍,最后我们通过web文件夹下的menu_config.js导出该菜单结构:
import home from './home/menu_config';
import archives from './archives/menu_config';
import categories from './categories/menu_config';
import about from './about/menu_config';
export default [home, archives, categories, about];
1.2 获取菜单配置信息
由于我们之前配置的path都是相对路径,因此我们需要将其转换为绝对路径,此外,我们还在菜单配置中加入了404菜单配置项;
@/components/404/menu_config.js:
import PageNotFound from './index';
export default {
title: '404',
icon: '',
path: '*',
component: PageNotFound,
invisible: true
}
这里配置了invisible指明*路由不需要出现在菜单项中。
utils/get_menus.js:
import _ from 'lodash';
import pageNotFoundMenu from '@/components/404/menu_config';
/**
* 解析menu_config 将配置路径由相对路径转为绝对路径
* @author zy
* @date 2020/4/8
* @param menus:menu_config配置
* @return contextPath:设置根路径
*/
const getMenus = (menus, contextPath) => {
const menusCopy = _.cloneDeep(menus);
const decodeMenus = (menusCopy, menuContextPath) => {
_.forEach(menusCopy, item => {
//获取当前菜单路径
let path = item.path ? `${menuContextPath}/${item.path}` : menuContextPath;
item.path = path.replace(/\/+/g, '/');
if (item.subMenus) {
decodeMenus(item.subMenus, path);
}
})
//给每个同阶菜单追加一个404 如/* /archives/* /archives/layout/*
if (menusCopy) {
const menu = _.cloneDeep(pageNotFoundMenu);
menu.path = (menuContextPath + '/*').replace(/\/+/g, '/');
menusCopy.push(menu);
}
}
decodeMenus(menusCopy, contextPath);
return menusCopy;
}
export default getMenus;
utils/index.js:
/**
* @author zy
* @date 2020/4/6
* @Description: 统用函数
*/
import getMenusFunctions from './get_menus';
export const getMenus = getMenusFunctions;
1.3 routes目录
我们修改routes/web.js:
/**
* @author zy
* @date 2020/4/5
* @Description: web路由
* 不懂的可以参考:https://segmentfault.com/a/1190000020812860
* https://reacttraining.com/react-router/web/api/Route
*/
import Layout from '@/layout/web';
import menus from '@/views/web/menu_config';
import {getMenus} from '@/utils';
import {WEB_ROOT_PATH} from '@/config';
/**
* web路由配置项
* @author zy
* @date 2020/4/5
*/
//web 菜单配置
export const webMenuConfig = getMenus(menus, WEB_ROOT_PATH);
//web route配置
export const webRouteConfig = {
title: 'home',
path: WEB_ROOT_PATH,
component: Layout, //根路径下配置web统一布局样式
subMenus: webMenuConfig
}
这里WEB_ROOT_PATH配置为'/'路径:
/**
* @author zy
* @date 2020/4/6
* @Description: 项目配置文件
*/
//web 根路径
export const WEB_ROOT_PATH = '/';
//导航栏博客名称
export const HEADER_BLOG_NAME = '我的博客';
其对应的组件为Layout,该组件是我们的布局组件,其主要包括顶部导航和侧边导航部分。
修改routes/index.js:
/**
* @author zy
* @date 2020/4/5
* @Description: 路由组件
*/
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { webRouteConfig } from './web';
import _ from 'lodash';
//保存所有路由配置的数组
const routeConfig = [webRouteConfig]
/**
* 路由配置
* @author zy
* @date 2020/4/5
*/
export default function () {
/**
* 生成路由嵌套结构
* @author: zy
* @date: 2020-03-05
* @param routeConfig: 路由配置数组
*/
const renderRouters = (routeConfig) => {
const routes = [];
//遍历每一个路由项
_.forEach(routeConfig, item => {
//这里使用了嵌套路由
routes.push(
<Route
key={item.path}
path={item.path}
component={() =>
<div className={item.title}>
{item.component && <item.component />}
{item.subMenus && renderRouters(item.subMenus)}
</div>
}
exact={item.subMenus ? false : true}
/>
);
});
return <Switch>{routes}</Switch>;
};
return renderRouters(routeConfig);
}
我们可以输出webRouteConfig:
二、Layout组件开发
上面我们已经说过WEB_ROOT_PATH路由,对应的组件为Layout,其中主要包括顶部导航和侧边导航部分,这里我们将尝试开发顶部导航功能:
我们将顶部导航拆分为两个组件Left,Right;Right组件拆分为Serch、NavBar、UserInfo三个组件;
我们在layout下创建web文件夹,其目录如下:
2..1 web/index.js
/**
* @author zy
* @date 2020/4/6
* @Description: web页面布局
*/
import React from 'react';
import {Layout, Row, Col} from 'antd';
import Header from './header';
// 响应式
const siderLayout = {xxl: 4, xl: 5, lg: 5, sm: 0, xs: 0}
const contentLayout = {xxl: 20, xl: 19, lg: 19, sm: 24, xs: 24}
/**
* Web布局组件
* @author zy
* @date 2020/4/6
*/
const WebLayout = props => {
return (
<Layout >
<Header/>
<Row>
<Col {...siderLayout}>
</Col>
<Col {...contentLayout}>
</Col>
</Row> </Layout>
)
}
export default WebLayout;
2.2 web/header/index.js
/**
* @author zy
* @date 2020/4/6
* @Description: web 头部布局
*/
import React from 'react';
import {Layout, Row, Col} from 'antd';
import Left from './left';
import Right from './right';
import styles from './styles.scss';
const Header = Layout.Header;
/**
* 头部布局组件
* @author zy
* @date 2020/4/6
*/
const WebHeader = () => {
// 响应式 xxl:超大屏 一行显示24/4列 xl:大屏一行显示24/5 ...
const responsiveLeft = {xxl: 4, xl: 5, lg: 5, sm: 4, xs: 24};
const responsiveRight = {xxl: 20, xl: 19, lg: 19, sm: 20, xs: 0};
return (
<Header id='app-header' className={styles.appHeader}>
<Row>
<Col {...responsiveLeft}>
<Left/>
</Col>
<Col {...responsiveRight}>
<Right/>
</Col>
</Row>
</Header>
)
}
export default WebHeader;
2.3 web/header/styles.scss
@import '@/styles/other.scss';
.appHeader {
padding: 0;
background: #fff;
box-shadow: 0 2px 8px $headerBoxShadowColor;
}
这里我们引入了@/styles/other.scss文件:
/**
* @author zy
* @date 2020/4/7
* @Description: 所有颜色定义
*/
//头部颜色
$headerColor: rgba(0, 0, 0, .85);
$headerBoxShadowColor: #f0f1f2;
//分割线颜色
$dividerColor: rgb(235, 237, 240);
//图标颜色
$searchIconColor: #ced4d9;
//占位符颜色
$placeholderColor: #a3b1bf;
//主页颜色
$homeBasicColor: #0cb7d5;
三、Left组件
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)