猴爪许愿:希望后端给我接口
项目是有后端的,但是由于是同步的开发,没办法随时随地和后端沟通,和后端约定一个数据的表,前端项目在实现的时候用JsonServer模拟后端数据
要使用 ,先安装
json-server --watch db.json
可以在npm上面搜索
json-server - npmhttps://www.npmjs.com/package/json-serverJson-server是基于node重新封装的一个框架
有查询的功能:比如这样:localhost:8000/posts?id=111
这就是根据属性筛选
开启Jsonserver:
json-server --watch test.json
import React from 'react';
import { Button } from "antd";
import 'axios'
import axios from 'axios';
function Home() {
const ajax = ()=>{
//拿取数据
axios.get("https://localhost:3000/posts/2").then(res=>{
console.log(res.data)
})
// 插入数据
axios.post("http://localhost:3000/posts",{
title:"hello",
author:"lizhi"
})
}
return (
<div>
<Button type='primary' onClick={ajax}>Button</Button>
</div>
);
}
export default Home;
增数据
import React from 'react';
import { Button } from "antd";
import 'axios'
import axios from 'axios';
function Home() {
const ajax = ()=>{
//拿取数据
// _embed
axios.get("http://localhost:3000/posts?_embed=comments").then(res=>{
console.log(res.data)
})
// _expand
// axios.get("http://localhost:3000/comments?_expand=post").then(res=>{
// console.log(res.data)
// })
// // 插入数据
// axios.post("http://localhost:3000/posts",{
// id:1,
// title:"hello",
// author:"lizhi"
// })
}
return (
<div>
<Button type='primary' onClick={ajax}>Button</Button>
</div>
);
}
export default Home;
后端SideMenu
import React, { useState, useEffect } from 'react'
import { Layout, theme } from 'antd'
import './index.css'
import {
UploadOutlined,
UserOutlined,
VideoCameraOutlined,
SettingOutlined,
} from '@ant-design/icons'
import { Switch } from 'antd'
// import SubMenu from 'antd/es/menu/SubMenu'
import { useNavigate } from 'react-router-dom' // 引入 useNavigate
import axios from 'axios'
import { Menu } from 'antd';
const { SubMenu } = Menu;
const { Header, Content, Sider } = Layout
// const menuList = [
// {
// key: '/home',
// title: '首页',
// icon: <UserOutlined />,
// },
// {
// key: '/user-manage',
// title: '用户管理',
// icon: <UserOutlined />,
// children: [
// {
// key: '/user-manage/list',
// title: '用户列表',
// icon: <UserOutlined />,
// },
// ],
// },
// {
// key: '/right-manage',
// title: '权限管理',
// icon: <UserOutlined />,
// children: [
// {
// key: '/right-manage/role/list',
// title: '角色列表',
// icon: <UserOutlined />,
// },
// {
// key: '/right-manage/right/list',
// title: '权限列表',
// icon: <UserOutlined />,
// },
// ],
// },
// ]
function SideMenu(props) {
const [menu, setMenu] = useState([])
useEffect(() => {
axios.get('http://localhost:3000/rights?_embed=children').then((res) => {
console.log(res.data)
setMenu(res.data)
})
},[])
const [collapsed, setCollapsed] = useState(false)
const navigate = useNavigate() // 使用 useNavigate 获取 navigate 函数
const onClick = (e) => {
console.log('click ', e)
}
const renderMenu = (menuList) => {
return menuList.map((item) => {
if (item.children) {
return (
<SubMenu key={item.key} icon={item.icon} title={item.title}>
{renderMenu(item.children)}
</SubMenu>
)
}
return (
<Menu.Item
key={item.key}
icon={item.icon}
onClick={() => {
navigate(item.key) // 使用 navigate 进行导航
}}
>
{item.title}
</Menu.Item>
)
})
}
return (
<Sider trigger={null} collapsible collapsed={false}>
<div className="logo">新闻发布系统</div>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['3']}
onClick={onClick}
defaultOpenKeys={['sub1']}
>
{renderMenu(menu)}
</Menu>
</Sider>
)
}
export default SideMenu
用test.json模拟后端的数据:
如果没有配置permission字段的没有必要渲染(没有资格点过去)
import React, { useState, useEffect } from 'react'
import { Layout, Menu } from 'antd'
import { useNavigate } from 'react-router-dom'
import axios from 'axios'
import {
UserOutlined,
SettingOutlined,
UploadOutlined,
VideoCameraOutlined,
AuditOutlined,
FormOutlined,
HomeOutlined,
} from '@ant-design/icons'
const { SubMenu } = Menu
const { Sider } = Layout
// **手动映射菜单项对应的图标**
const iconMap = {
首页: <HomeOutlined />,
用户管理: <UserOutlined />,
用户列表: <UserOutlined />,
权限管理: <SettingOutlined />,
新闻管理: <FormOutlined />,
审核管理: <AuditOutlined />,
发布管理: <UploadOutlined />,
}
function SideMenu() {
const [menu, setMenu] = useState([])
useEffect(() => {
axios.get('http://localhost:3000/rights?_embed=children').then((res) => {
setMenu(res.data)
})
}, [])
const navigate = useNavigate()
const checkPermission = (item) => {
// 检查用户是否具有访问权限
return item.pagepermisson === 1
}
const renderMenu = (menuList) => {
return menuList.map((item) => {
const icon = iconMap[item.title] || <VideoCameraOutlined /> // 默认图标
if (item.children && checkPermission(item)) {
return (
<SubMenu key={item.key} icon={icon} title={item.title}>
{renderMenu(item.children)}
</SubMenu>
)
}
return (
checkPermission(item) &&
<Menu.Item key={item.key} icon={icon} onClick={() => navigate(item.key)}>
{item.title}
</Menu.Item>
)
})
}
return (
<Sider trigger={null} collapsible>
<div className="logo">新闻发布系统</div>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
{renderMenu(menu)}
</Menu>
</Sider>
)
}
export default SideMenu
这样以后就成功了,以及图标也可以正确的显示
接下来要解决的是首页不可折叠的问题
import React, { useState, useEffect } from 'react'
import { Layout, Menu } from 'antd'
import { useNavigate } from 'react-router-dom'
import axios from 'axios'
import {
UserOutlined,
SettingOutlined,
UploadOutlined,
VideoCameraOutlined,
AuditOutlined,
FormOutlined,
HomeOutlined,
} from '@ant-design/icons'
const { SubMenu } = Menu
const { Sider } = Layout
// **手动映射菜单项对应的图标**
const iconMap = {
首页: <HomeOutlined />,
用户管理: <UserOutlined />,
用户列表: <UserOutlined />,
权限管理: <SettingOutlined />,
新闻管理: <FormOutlined />,
审核管理: <AuditOutlined />,
发布管理: <UploadOutlined />,
}
function SideMenu() {
const [menu, setMenu] = useState([])
useEffect(() => {
axios.get('http://localhost:3000/rights?_embed=children').then((res) => {
setMenu(res.data)
})
}, [])
const navigate = useNavigate()
const checkPermission = (item) => {
// 检查用户是否具有访问权限
return item.pagepermisson === 1
}
const renderMenu = (menuList) => {
return menuList.map((item) => {
const icon = iconMap[item.title] || <VideoCameraOutlined /> // 默认图标
if (item.children?.length>0 && checkPermission(item)) {
return (
<SubMenu key={item.key} icon={icon} title={item.title}>
{renderMenu(item.children)}
</SubMenu>
)
}
return (
checkPermission(item) &&
<Menu.Item key={item.key} icon={icon} onClick={() => navigate(item.key)}>
{item.title}
</Menu.Item>
)
})
}
return (
<Sider trigger={null} collapsible>
<div className="logo">新闻发布系统</div>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
{renderMenu(menu)}
</Menu>
</Sider>
)
}
export default SideMenu
进行链式判断,如果没有的话就不判断长度
然后是进行一些样式方面的优化,把滚动条给该样式(需安装antd,因为Vite默认不支持~的写法,那种写法是Webpack的)
@import 'antd/dist/reset.css';
::-webkit-scrollbar{width: 5px;height: 5px;position: absolute;}
::-webkit-scrollbar-thumb{background-color: #1890ff;}
::-webkit-scrollbar-track{background-color: #ddd;}
接下来根据路径选择渲染哪一部分高亮
重定向会导致高亮显示失效,是因为加上default会变成非受控组件,而去掉default就称为受控的了(受控:外部状态改变,内部也会受到影响
非受控:外部状态改变只对第一次的造成影响)
import React, { useState, useEffect } from 'react'
import { Layout, Menu } from 'antd'
import { useNavigate } from 'react-router-dom'
import axios from 'axios'
import {
UserOutlined,
SettingOutlined,
UploadOutlined,
VideoCameraOutlined,
AuditOutlined,
FormOutlined,
HomeOutlined,
} from '@ant-design/icons'
import './index.css'
import { useLocation } from 'react-router-dom'
const { SubMenu } = Menu
const { Sider } = Layout
// **手动映射菜单项对应的图标**
const iconMap = {
首页: <HomeOutlined />,
用户管理: <UserOutlined />,
用户列表: <UserOutlined />,
权限管理: <SettingOutlined />,
新闻管理: <FormOutlined />,
审核管理: <AuditOutlined />,
发布管理: <UploadOutlined />,
}
function SideMenu() {
const [menu, setMenu] = useState([])
const location = useLocation() // 获取当前的路径
useEffect(() => {
axios.get('http://localhost:3000/rights?_embed=children').then((res) => {
setMenu(res.data)
})
}, [])
const navigate = useNavigate()
const checkPermission = (item) => {
// 检查用户是否具有访问权限
return item.pagepermisson === 1
}
const renderMenu = (menuList) => {
return menuList.map((item) => {
const icon = iconMap[item.title] || <VideoCameraOutlined /> // 默认图标
if (item.children?.length > 0 && checkPermission(item)) {
return (
<SubMenu key={item.key} icon={icon} title={item.title}>
{renderMenu(item.children)}
</SubMenu>
)
}
return (
checkPermission(item) && (
<Menu.Item
key={item.key}
icon={icon}
onClick={() => navigate(item.key)}
>
{item.title}
</Menu.Item>
)
)
})
}
//找到路径
const selectKeys = [location.pathname]
//分割字符串
const openKeys = ['/' + location.pathname.split('/')[1]]
return (
<Sider trigger={null} collapsible>
<div style={{ display: 'flex', height: '100%', flexDirection: 'column' }}>
<div className="logo">新闻发布系统</div>
<div style={{ flex: 1, overflow: 'auto' }}>
<Menu
theme="dark"
mode="inline"
selectedKeys={selectKeys}
defaultOpenKeys={openKeys}
>
{renderMenu(menu)}
</Menu>
</div>
</div>
</Sider>
)
}
export default SideMenu