程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

博客管理系统开发 -- 顶部导航栏开发

这一节我将带领大家,来开发博客管理系统的顶部导航功能,其效果最终如下:

一、路由优化

上一节我们介绍了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-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
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-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(745)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示