从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失效的情况,剩下的功能和优化会更新在后续,喜欢的小伙伴们点点关注点点赞,你们的支持就是我的动力

  • 56
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
《大鱼吃小鱼》是一款简单而有趣的游戏,适合初学者学习Java游戏开发。下面我将手把手教你如何用Java开发这款游戏,并提供相应的源码。 步骤一:创建游戏窗口和游戏主类 首先,我们需要创建游戏的窗口,可以使用Java提供的Swing框架来实现。创建一个GameWindow类,继承JFrame类,并在构造方法中设置窗口的基本属性。 步骤:添加游戏画布 在GameWindow类中,创建一个GameCanvas类,继承JPanel类,并重写paintComponent()方法,在此方法中实现游戏场景的绘制,包括大鱼、小鱼和其他游戏元素。 步骤三:添加游戏逻辑 在GameWindow类中,添加游戏逻辑的处理方法,包括大鱼的移动、小鱼的生成和碰撞检测等。 步骤四:添加游戏控制 在GameWindow类中,添加游戏控制的方法,包括键盘事件的处理和游戏状态的切换等。 步骤五:运行游戏 在GameWindow类中,添加一个main()方法,创建游戏窗口对象,并启动游戏循环。 以上是《大鱼吃小鱼》游戏的基本开发步骤,下面提供相应的源码供参考: ```java import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class GameWindow extends JFrame implements KeyListener{ private GameCanvas gameCanvas; private boolean isRunning; public GameWindow(){ super("大鱼吃小鱼"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); addKeyListener(this); gameCanvas = new GameCanvas(); add(gameCanvas, BorderLayout.CENTER); isRunning = true; } public void start(){ while(isRunning){ update(); gameCanvas.repaint(); try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } } } public void update(){ // 游戏逻辑更新 } public void keyPressed(KeyEvent e){ // 键盘按下事件处理 } public void keyReleased(KeyEvent e){ // 键盘释放事件处理 } public void keyTyped(KeyEvent e){ // 键盘输入事件处理 } public static void main(String[] args){ GameWindow gameWindow = new GameWindow(); gameWindow.setVisible(true); gameWindow.start(); } } class GameCanvas extends JPanel{ protected void paintComponent(Graphics g){ super.paintComponent(g); // 游戏场景绘制 } } ``` 通过以上源码和步骤,我们可以实现《大鱼吃小鱼》游戏的基本开发,通过添加更多的游戏逻辑和个性化设计,可以进一步完善这款游戏。希望对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值