从0开始手把手教你做极客园项目(二)——首页功能实现


前言

上一篇文章中(从0开始手把手教你做极客园项目(一)——登录功能实现)详细讲解了登录功能,在登录跳转后就是首页,本文详细讲解跳转到首页的功能实现源码地址极客园github

1.首页静态结构准备

在Layout/index.tsx里参考antd的官方文档将首页的界面搭建,items表示首页右边三个导航栏的切换

import {
    Layout, Menu, Popconfirm } from 'antd'
import {
   
  HomeOutlined,
  DiffOutlined,
  EditOutlined,
  LogoutOutlined,
} from '@ant-design/icons'
import './index.scss'

const {
    Header, Sider } = Layout

const items = [
  {
   
    label: '首页',
    key: '1',
    icon: <HomeOutlined />,
  },
  {
   
    label: '文章管理',
    key: '2',
    icon: <DiffOutlined />,
  },
  {
   
    label: '创建文章',
    key: '3',
    icon: <EditOutlined />,
  },
]

const GeekLayout = () => {
   
  return (
    <Layout>
      <Header className="header">
        <div className="logo" />
        <div className="user-info">
          <span className="user-name">zwb</span>
          <span className="user-logout">
            <Popconfirm title="是否确认退出?" okText="退出" cancelText="取消">
              <LogoutOutlined /> 退出
            </Popconfirm>
          </span>
        </div>
      </Header>
      <Layout>
        <Sider width={
   200} className="site-layout-background">
          <Menu
            mode="inline"
            theme="dark"
            defaultSelectedKeys={
   ['1']}
            items={
   items}
            style={
   {
    height: '100%', borderRight: 0 }}></Menu>
        </Sider>
        <Layout className="layout-content" style={
   {
    padding: 20 }}>
          内容
        </Layout>
      </Layout>
    </Layout>
  )
}
export default GeekLayout

对应的index.scss样式文件如下

.ant-layout {
   
    height: 100%;
  }
  
  .header {
   
    padding: 0;
  }
  
  .logo {
   
    width: 200px;
    height: 60px;
    background: url('~@/assets/logo.png') no-repeat center / 160px auto;
  }
  
  .layout-content {
   
    overflow-y: auto;
  }
  
  .user-info {
   
    position: absolute;
    right: 0;
    top: 0;
    padding-right: 20px;
    color: #fff;
    
    .user-name {
   
      margin-right: 20px;
    }
    
    .user-logout {
   
      display: inline-block;
      cursor: pointer;
    }
  }
  .ant-layout-header {
   
    padding: 0 !important;
  }

同时安装normalize.css用于消除浏览器默认样式,在根目录下的index.tsx里引入,并且创建一个index.scss文件用于设置整个界面充满的样式

npm install normalize.css
import 'normalize.css'
import './index.scss'
html,
body {
   
  margin: 0;
  height: 100%;
}

#root {
   
  height: 100%;
}

在这里插入图片描述

2.配置二级路由

首先在pages里创建三个二级路由界面组件,分别表示首页,文章管理,创建文章的模块,rafce初始化组件,在router/index.tsx里添加layout路由的children表示二级路由,并在layout组件里导出二级路由

  {
   
        path: '/',
        element: <AuthRouter><Layout /></AuthRouter>,
        children: [
            {
   
                index:true,//默认二级路由
                element: <Home />
            }, 
            {
   
                path: 'article',
                element: <Article />
            }, 
            {
   
                path: 'publish',
                element: <Publish />
            }
        ]
    },
 <Layout className="layout-content" style={
   {
    padding: 20 }}>
          <Outlet/>//二级路由出口
        </Layout>

在这里插入图片描述

3.点击跳转路由

实现跳转路由需要拿到当前点击的二级路由地址,可以将原来items里的key换成路径地址,然后通过添加点击函数获取到当前点击的key,利用navigate方法实现路由跳转

const items = [
  {
   
    label: '首页',
    key: '/',
    icon: <HomeOutlined />,
  },
  {
   
    label: '文章管理',
    key: '/article',
    icon: <DiffOutlined />,
  },
  {
   
    label: '创建文章',
    key: '/publish',
    icon: <EditOutlined />,
  },
]
const navigate=useNavigate()
<Menu
            mode="inline"
            theme="dark"
            defaultSelectedKeys={
   ['1']}
            items={
   items}
            style={
   {
    height: '100%', borderRight: 0 }}
            onClick={
   (router)=>{
   navigate(router.key)}}//点击跳转到相应key的路径路由
            ></Menu>

在这里插入图片描述

4.菜单栏高光

原来的菜单栏是只有点击的时候才会显示高光,但是在刷新界面的时候高光消失了,要解决这个问题可以使用useLocation获取到当前路径,在antd的Menu组件中增加一个selectedKeys这个属性,代表当前选中的值

const location=useLocation()
  const selected=location.pathname
<Menu
            mode="inline"
            theme="dark"
            selectedKeys={
   [selected]}
            items={
   items}
            style={
   {
    height: '100%', borderRight: 0 }}
            onClick={
   (router)=>{
   navigate(router.key)}}
            ></Menu>

5.渲染用户信息

获取用户信息我们可以使用redux状态管理来对用户信息进行保存,在user.tsx文件中添加用户的状态和设置状态的函数,并通过一个异步方法获取后端的数据,在组件Layout/index.tsx中通过useEffect钩子函数在页面加载的时候就进行渲染

interface User {
   
    id: string;
    photo: string;
    name: string;
    mobile: string;
    gender: number;
    birthday: string;
    intro: string | null;
  }
const userStore = createSlice({
   
    name: 'user',
    initialState: {
   
        token: getToken() || '',
        user:{
   } as User
    },
    reducers: {
   
        setToken(state, action) {
   
            state.token = action.payload
            _setToken(action.payload)
        },
        setUser(state,action){
   
            state.user=action.payload
        }
    }
})
const fetchUser: () => (dispatch: Dispatch) => Promise<void> = () => {
   
    return async (dispatch: Dispatch) => {
   
      const res= await request.get('/user/profile')
      dispatch(setUser(res.data))
    }
}
const dispatch = useAppDispatch()
  useEffect(() => {
   
   dispatch(fetchUser())
  },[dispatch])

在这里插入图片描述
可以看见redux状态里已经有了后端取到的user对象,使用useAppSelector函数获取状态数据进行渲染

const name =useAppSelector(state=>state.user.user.name)
<span className="user-name">{
   name}</span>

在这里插入图片描述

6.退出登录功能

退出登录时,redux状态里关于所有用户的信息都要删除,并且localstorage里的token也要清除,所以在user.tsx的reducers中添加一个清除的函数

  exitUser(state){
   
            state.token=''
            state.user={
   } as User
            removeToken()
        }

在组建中绑定点击函数,点击函数调用清除的方法和跳转到登录界面

<Popconfirm title="是否确认退出?" okText="退出" cancelText="取消" onConfirm={
   onconfirm}>
              <LogoutOutlined /> 退出
            </Popconfirm>
const onconfirm=()=>{
   
    dispatch(exitUser())
    navigate('/login')
  }

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

7.设置token失效

用户在长时间未在网站做任何操作,且规定时间到达时,当前的token失效,token失效后,后端返回401状态码,而前端需要监控这个状态,在拦截器中监控401,清除token返回登录,在utils里的request.tsx里的响应拦截器添加清除和跳转界面以及刷新界面的操作

request.interceptors.response.use((response)=> {
   
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response.data
  }, (error)=> {
   
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    if(error.response.status===401){
   
      removeToken()
      router.navigate('/login')
      window.location.reload()
    }
    return Promise.reject(error)
})

可以手动模拟token失效,自行在localstorage里的token修改,然后手动按下刷新

8.Home渲染图表数据

安装echarts

npm install echarts 

封装一个柱状图组件,在Home里添加一个components文件夹,新建一个BarChart.tsx文件,文件当中引入echarts官网的柱状图模板,添加自己需要改的数据,使用useRef与节点进行绑定,

import * as echarts from 'echarts';
import {
    useEffect, useRef } from 'react';
interface Title{
   
  title:string
}
const BarChart = ({
    title}:Title) => {
   
  const chartRef = useRef(null)
  useEffect(() => {
   
    const chartDom = chartRef.current
    const myChart = echarts.init(chartDom);//初始化生成图表实例对象

    const option = {
   
      title: {
   
        text: title
      },
      xAxis: {
   
        type: 'category',
        data: ['vue', 'react', 'angular']
      },
      yAxis: {
   
        type: 'value'
      },
      series: [
        {
   
          data: [10, 40, 70],
          type: 'bar'
        }
      ]
    };

    option && myChart.setOption(option);
  })
  return (
    <div><div ref={
   chartRef} style={
   {
    width: '500px', height: '400px' }}></div></div>
  )
}

export default BarChart

在父组件中index.tsx中调用组件,通过props传入title参数

<div style={
   {
   display:"flex",flexDirection:"row"}}>
      <BarChart title="三大框架满意度"/>
      <BarChart title="三大框架使用度"/>
      </div>

在这里插入图片描述

总结

本次实现了首页的基本功能,例如菜单跳转,二级路由,高亮显示以及图表数据显示(这里的图表数据有需要的话可以跟后端获取),再进行了优化例如token失效的情况,剩下的功能和优化会更新在后续,喜欢的小伙伴们点点关注点点赞,你们的支持就是我的动力

最近更新

  1. TCP协议是安全的吗?

    2024-02-06 23:56:01       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-06 23:56:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-06 23:56:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-06 23:56:01       18 阅读

热门阅读

  1. rtt设备驱动框架学习-spi总线和设备

    2024-02-06 23:56:01       29 阅读
  2. TCP和UDP相关问题(重点)(2)

    2024-02-06 23:56:01       32 阅读
  3. 配合后端-开发工具(在线)

    2024-02-06 23:56:01       34 阅读
  4. pnpm + vite 从外网迁移到内网环境开发

    2024-02-06 23:56:01       40 阅读
  5. Git学习笔记-- amend 详解

    2024-02-06 23:56:01       29 阅读
  6. 计算机网络相关题目及答案(第一章)

    2024-02-06 23:56:01       29 阅读
  7. 计算机网络相关题目及答案(第二章)

    2024-02-06 23:56:01       27 阅读
  8. 浅谈null和undefined的异同

    2024-02-06 23:56:01       33 阅读
  9. 非springboot 使用aop 切面

    2024-02-06 23:56:01       31 阅读
  10. C语言——S/顺序表专题

    2024-02-06 23:56:01       31 阅读