React后台管理(七)-- layout布局相关组件封装,以及涉及功能实现


前言

本文将详细介绍页面布局的搭建过程,以及其中涉及的相关功能。主要包括头部、侧边栏和内容区域。我们将讲解其中用到的相关功能:如何注册子路由、监听路由变化、实现侧边栏收缩功能、observer监听器的使用、在头部展示和更新个人信息以及使用MobX进行信息管理、登录、登出和记录路由等相关功能的实现。


一、Layout父级组件封装

分析:
(1)主要分为侧边栏,头部,内容;
(2)使用Outlet来注册子路由
(3)使用useEffect,useLocation监听路由,当路由变化时,重新记录当前路由
(4)调用store侧边栏状态并使用
注:store方法请查看之前文章:React后台管理(五)-- 状态管理工具mobx安装以及本项目登录,表格,用户信息状态管理封装使用

// @/layout/index.jsx
import React, { useState, useEffect } from "react";
import { Outlet, useLocation } from "react-router-dom";
import { Layout, Menu } from "antd";
import { observer } from "mobx-react-lite";
import useStore from "@/store";
import items from "@/components/menuItem.jsx";
import MyHeader from "@/layout/components/header/index.jsx";
import "./index.scss";
const { Sider, Content } = Layout;
const LayOut = () => {
 const { UserStore, TableStore } = useStore();
 const [defaultOpenKeys] = useState(["Workbench", "chainManage"]);
 const { pathname } = useLocation();
 // 仅在pathname变化时执行一次
 useEffect(() => {
   TableStore.SET_CURRENT_PATH(pathname); // 执行副作用,设置当前路由
 }, [pathname]); // 依赖于location变化来执行副作用
 const collapsed = UserStore.state.collapse; // store: 侧边栏展开收起状态
 return (
   <Layout>
     <Sider trigger={null} collapsible width="208" collapsedWidth="80" collapsed={collapsed} className="sider">
       {!collapsed ? <div className="logo" /> : <div className="logo1" />}
       <Menu theme="dark" mode="inline" defaultSelectedKeys={[pathname]} defaultOpenKeys={defaultOpenKeys} items={items} />
     </Sider>
     <Layout className="site-layout">
       <MyHeader />
       <Content>
         <Outlet />
       </Content>
     </Layout>
   </Layout>
 );
};
export default observer(LayOut);
// 样式文件如下
// ./index.scss
.ant-layout {
 height: 100%;
}
.ant-layout-sider {
}
.sider {
 padding: 0;
}
.logo,
.logo1 {
 width: 155px;
 height: 22px;
 background: url("~@/assets/s-logo.png") no-repeat center;
 margin: 16px auto;
}
.logo1 {
 width: 36px;
 height: 36px;
 background: url("~@/assets/s-logo1.png") no-repeat center;
}

.ant-layout-header svg {
 font-size: 15px;
 margin-left: 15px;
}

.user-name {
 position: absolute;
 right: 5%;
 margin-right: 10px;
 margin-left: 22px;
}
.user-logout {
 position: absolute;
 right: 2%;
 display: inline-block;
 cursor: pointer;
}

#components-layout-demo-custom-trigger .trigger {
 padding: 0 24px;
 font-size: 18px;
 line-height: 64px;
 cursor: pointer;
 transition: color 0.3s;
}

#components-layout-demo-custom-trigger .trigger:hover {
 color: #1890ff;
}

#components-layout-demo-custom-trigger .logo {
 height: 32px;
 margin: 16px;
 background: rgba(255, 255, 255, 0.3);
}

二、MyHeader头部组件封装

分析:
(1)使用observer包裹函数组件,使其可以监听状态变化,实时更新
(2)使用createElement创建一个可收缩元素,并添加点击事件,实现展开收起功能
(3)调用状态管理方法setCollapse实时更新收缩状态
(4)引入用户信息函数组件UserInfo.jsx
注:setCollapse方法请查看之前文章:React后台管理(五)-- 状态管理工具mobx安装以及本项目登录,表格,用户信息状态管理封装使用

// @/layout/components/header/index.jsx
import React from "react";
import { observer } from "mobx-react-lite";
import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons";
import useStore from "@/store";
import UserInfo from "@/layout/components/header/components/user/index.jsx";
import "./index.scss";

const MyHeader = (props) => {
  const { UserStore } = useStore();
  // store: 侧边栏展开收起状态
  const collapsed = UserStore.state.collapse;
  return (
    <>
      <div className="layout-header">
        <div className="header-left">
          {React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
            className: "trigger",
            onClick: () => UserStore.setCollapse(),
          })}
        </div>
        <div className="header-menu">
          <UserInfo />
        </div>
      </div>
    </>
  );
};
export default observer(MyHeader);

// @/layout/components/header/index.jsx
.layout-header {
  position: relative;
  display: flex;
  align-items: center;
  height: 40px;
  padding: 0 24px;
  background-color: #fff;
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.05);
  .header-left {
    flex: 1;
    width: 0;
    display: flex;
    align-items: center;
  }
  .header-menu {
    display: flex;
    align-items: center;
  }
}

三、UseInfo用户下拉信息组件封装

分析:
(1)使用observer包裹函数组件,以监听个人信息变化并实时更新
(2)调用LoginStore,实现退出登录功能
注:LoginStore实例方法请查看之前文章:React后台管理(五)-- 状态管理工具mobx安装以及本项目登录,表格,用户信息状态管理封装使用

// @/layout/components/header/components/user/index.jsx
import { Modal, Dropdown } from "antd";
import useStore from "@/store";
import { useNavigate } from "react-router-dom";
import { observer } from "mobx-react-lite";
import { ExclamationCircleFilled } from "@ant-design/icons";
import "./index.scss";
const { confirm } = Modal;
const UserInfo = () => {
  const { LoginStore } = useStore();
  const navigation = useNavigate();
  const loginOut = () => {
    confirm({
      title: "退出登录",
      icon: <ExclamationCircleFilled />,
      content: <>确定退出登录</>,
      onOk() {
        LoginStore.logOutAction().then(() => {
          navigation("/login", { replace: true });
        });
      },
      onCancel() {
        console.log("Cancel");
      },
    });
  };
  const items = [
    {
      key: "1",
      label: (
        <div className="meta">
          <img src={require("@/assets/admin.png")} />
          <div>
            <h4 className="ellipse-1" title={LoginStore?.state?.username}>
              <strong>{LoginStore?.state?.username}</strong>
            </h4>
            <span className="ellipse-1" title={LoginStore?.state?.role}>
              {LoginStore?.state?.role}
            </span>
          </div>
        </div>
      ),
    },
    {
      key: "2",
      label: (
        <a>
          <i className="iconfont icon-user-2"></i>个人中心
        </a>
      ),
    },
    {
      key: "3",
      label: (
        <a>
          <i className="iconfont icon-dingdan"></i>平台资料
        </a>
      ),
    },
    {
      key: "4",
      label: (
        <a onClick={loginOut}>
          <i className="iconfont icon-tuichu"></i>退出登录
        </a>
      ),
    },
  ];
  return (
    <Dropdown menu={{ items }} overlayClassName={"userinfo-popup"} placement="bottomRight" arrow>
      <div>
        <div className="user-info">
          <img src={require("@/assets/admin.png")} />
          <div>{LoginStore?.state?.username}</div>
        </div>
      </div>
    </Dropdown>
  );
};

export default observer(UserInfo);

// @/layout/components/header/components/user/index.scss
.user-info {
  padding-left: 16px;
  height: 40px;
  display: flex;
  align-items: center;
  img {
    width: 24px;
    height: 24px;
    border-radius: 100px;
    margin-right: 8px;
  }
  span,
  strong {
    display: block;
    line-height: 1;
    font-size: 14px;
  }
  span {
    margin-top: 4px;
    font-size: 12px;
    color: #666666;
  }
}
.userinfo-popup {
  background-color: #fff;
  box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.15);
  min-width: 164px !important;
  li {
    &:not(:first-child) {
      position: relative;
      display: flex;
      align-items: center;
      height: 32px;
      padding: 0 12px;
      color: #555555;
      font-size: 14px;
      margin: 4px 0;
      cursor: pointer;
      &:hover {
        background-color: #f2f2f2;
      }
      i {
        margin-right: 8px;
      }
    }
    &:nth-child(1):hover {
      cursor: initial;
      background-color: #ffffff !important;
    }
    &:nth-last-child(1) {
      border-top: 1px solid #e9e9e9;
      padding-top: 20px !important;
      padding-bottom: 20px !important;
    }
  }
  .meta {
    display: flex;
    align-items: center;
    padding-bottom: 10px;
    img {
      width: 36px;
      height: 36px;
      border-radius: 100px;
    }
    > div {
      padding-left: 8px;
      flex: 1;
      width: 0;
      span {
        font-size: 12px;
        color: #666666;
      }
    }
  }
}

四、效果展示

在这里插入图片描述
在这里插入图片描述


总结

下一篇讲【开发页面前准备—插槽以及函数组件传值】。关注本栏目,将实时更新。

  • 36
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值