SideBar
(1) store/collapse.tsx
tsx
import { proxy } from "valtio";
interface CollapseState {
/** 侧边栏是否收缩 */
collapsed: boolean;
/** 切换收缩状态 */
toggle: () => void;
/** 设置收缩状态 */
setCollapsed: (collapsed: boolean) => void;
}
export const collapseStore = proxy<CollapseState>({
collapsed: true,
toggle() {
this.collapsed = !this.collapsed;
},
setCollapsed(collapsed: boolean) {
this.collapsed = collapsed;
},
});(2) components/SideBar
SideBar/index.tsx
tsx
import React from "react";
import {
AppstoreOutlined,
ContainerOutlined,
DesktopOutlined,
MailOutlined,
PieChartOutlined,
} from "@ant-design/icons";
import type { MenuProps } from "antd";
import { Menu } from "antd";
import { useSnapshot } from "valtio";
import { collapseStore } from "@/store/collapse";
type MenuItem = Required<MenuProps>["items"][number];
const items: MenuItem[] = [
{ key: "1", icon: <PieChartOutlined />, label: "Option 1" },
{ key: "2", icon: <DesktopOutlined />, label: "Option 2" },
{ key: "3", icon: <ContainerOutlined />, label: "Option 3" },
{
key: "sub1",
label: "Navigation One",
icon: <MailOutlined />,
children: [
{ key: "5", label: "Option 5" },
{ key: "6", label: "Option 6" },
{ key: "7", label: "Option 7" },
{ key: "8", label: "Option 8" },
],
},
{
key: "sub2",
label: "Navigation Two",
icon: <AppstoreOutlined />,
children: [
{ key: "9", label: "Option 9" },
{ key: "10", label: "Option 10" },
{
key: "sub3",
label: "Submenu",
children: [
{ key: "11", label: "Option 11" },
{ key: "12", label: "Option 12" },
],
},
],
},
];
const SideBar: React.FC = () => {
// 组件内订阅状态
const { collapsed } = useSnapshot(collapseStore);
return (
<Menu
defaultSelectedKeys={["1"]}
defaultOpenKeys={["sub1"]}
mode="inline"
theme="dark"
inlineCollapsed={collapsed}
items={items}
/>
);
};
export default SideBar;(3) layouts
index.tsx
- 至于图片随便找一张就行
tsx
import { Outlet } from "react-router-dom";
import { Layout, Watermark } from "antd";
import React from "react";
import { ContentWrapper, Logo } from "./layout.css";
import NavHeader from "@/components/NavHeader/index";
import NavFooter from "@/components/NavFooter/index";
const { Header, Content, Sider } = Layout;
import SideBar from "@/components/SideBar/index";
import { useSnapshot } from "valtio";
import { collapseStore } from "@/store/collapse";
import logoImg from "@/assets/images/logo.jpg";
import { css } from "@emotion/react";
const App: React.FC = () => {
const { collapsed } = useSnapshot(collapseStore);
const sidebarlog = () => {
if (collapsed) {
return (
<img
src={logoImg}
alt="logo"
css={css`
width: 40px;
height: 40px;
display: block;
align-self: center;
justify-self: center;
border-radius: 50%;
margin-bottom: 12px;
margin-top: 12px;
`}
/>
);
} else {
return <Logo>ReactCMS</Logo>;
}
};
return (
<Watermark content="翻版必究">
<Layout style={{ minHeight: "100vh" }}>
<Sider
breakpoint="lg"
width={200}
collapsedWidth={64}
collapsed={collapsed}
onBreakpoint={(broken) => {
console.log(broken);
}}
onCollapse={(collapsed, type) => {
console.log(collapsed, type);
}}
>
{sidebarlog()}
<SideBar />
</Sider>
<Layout>
<Header style={{ padding: 0, background: "#fff" }}>
<NavHeader></NavHeader>
</Header>
<Content style={{ margin: "24px 16px 0" }}>
<ContentWrapper style={{ padding: 24, minHeight: 360 }}>
<Outlet />
</ContentWrapper>
</Content>
<NavFooter></NavFooter>
</Layout>
</Layout>
</Watermark>
);
};
export default App;layout.css.tsx
tsx
import styled from "@emotion/styled";
export const Logo = styled.div`
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.2);
color: #fff;
line-height: 32px;
text-align: center;
`;
export const SubHeader = styled.div`
background: #fff;
`;
export const ContentWrapper = styled.div`
background: #fff;
`;(4) components/NavHeader
- 增加了点击事件
index.tsx
tsx
import {
MenuFoldOutlined,
DownOutlined,
MenuUnfoldOutlined,
} from "@ant-design/icons";
import { Breadcrumb, Switch, Dropdown, type MenuProps, Space } from "antd";
import { useState } from "react";
import { NavHeaderWrapper, NavLeft, NickName } from "./navheader.css";
import { useSnapshot } from "valtio";
import { collapseStore } from "@/store/collapse";
function NavHeader() {
// 组件内订阅状态
const { collapsed } = useSnapshot(collapseStore);
const [breadlist] = useState([
{ title: "首页", key: "1" },
{ title: "欢迎页", key: "2" },
]);
const items: MenuProps["items"] = [
{
key: "1",
label: "邮箱:2993222085@qq.com",
},
{
key: "2",
danger: true,
label: "退出登陆",
},
];
return (
<NavHeaderWrapper>
<NavLeft>
{collapsed ? (
<MenuUnfoldOutlined onClick={() => collapseStore.toggle()} />
) : (
<MenuFoldOutlined onClick={() => collapseStore.toggle()} />
)}
<Breadcrumb items={breadlist} style={{ marginLeft: 12 }} />
</NavLeft>
<div>
<Switch
checkedChildren="暗黑"
unCheckedChildren="默认"
style={{ marginRight: 12 }}
/>
<Dropdown
menu={{
items,
onClick: ({ key }) => {
console.log(`当前序号:${key},hello world`);
},
}}
trigger={["click"]}
>
<a onClick={(e) => e.preventDefault()}>
<NickName>
<Space>
七宗罪
<DownOutlined />
</Space>
</NickName>
</a>
</Dropdown>
</div>
</NavHeaderWrapper>
);
}
export default NavHeader;