React实例之完善布局菜单(一)

news2024/11/24 5:49:01

今天我们来用所学的知识来做一个布局菜单的组件, 针对这个组件我之前写过一个教程 React之布局菜单-CSDN博客,那个呢比较基础,这节课算是对那个教程的一个扩展和补充。这个实例讲完,这个系列就算告一段落了。先看效果在这里插入图片描述
这个教程要求对React知识的了解要求比较全面,如果你是跟着我这个系统文章一路学来的,应该就能跟得上学习进度。本教程内容很多,很详细,会分为几个章节来讲解。

安装

首先要安装MUI React RouterReact Redux这是必不可少的。我们除了会完成在开头的动图效果示例之外,还有较完整功能添加,所以,会用到一些没有讲过的功能。

设计前的考虑
  • 为了考虑到高度自定义这个特性,我们把菜单的配置以 json数组的形式进行配置。你可以把菜单配置放在服务器上,基于权限的考虑你甚至可以在后台根据用户权限的不同返回不同的菜单配置,实现角色的功能 。
  • 我们尽可能的将与业务代码无关的东西封装在组件内部,这样调用起来代码就很简洁。
  • 根据业务逻辑尽可能的细小化、模块化。
  • 所有UI元素都要适配暗黑模式,也就是两种颜色模式。
Bootstrap

前端是绕不开Css的,但是对于一个完整的项目来说,写Css就很繁琐,我的主张是,能偷懒就偷懒,不能偷懒想办法偷懒。这不,对于布局中的GridFlex 方面,Bootstrap 就提供了相当完美的功能了,我认为这方面它比MUI强许多,既然如此,何不做个拿来主义者呢,何苦自己为难自己呢。书回正传,回到我们的项目,在源目录(src) 下新建一个本章的实例目录:SMenu , 并在这个目录下新建目录 SCSS, 我们把网上下载的Bootstrap5.3的Css文件放到这个目录里。另外,我也提供了两个其它的两个css文件,目录结构如下所示:

在这里插入图片描述

关于Bootstrap的样式,请大家自行学习,此处不做详解。

以下是 components.css 的内容

.fade-enter {
    opacity: 0;
    transform: translateX(-100%);
  }
  .fade-enter-active {
    opacity: 1;
    transform: translateX(0%);
  }
  .fade-exit {
    opacity: 1;
    transform: translateX(0%);
  }
  .fade-exit-active {
    opacity: 0;
    transform: translateX(100%);
  }
  .fade-enter-active,
  .fade-exit-active {
    transition: opacity 500ms, transform 500ms;
  }
  
  
  .my-node-enter {
    opacity: 0;
  }
  .my-node-enter-active {
    opacity: 1;
    transition: opacity 200ms;
  }
  .my-node-exit {
    opacity: 1;
  }
  .my-node-exit-active {
    opacity: 0;
    transition: opacity 200ms;
  }

  /*
  *弹窗动画
  */
  .speedx-alert-enter {
    opacity: 0;
    transform: scale(0.9);
  }
  .speedx-alert-enter-active {
    opacity: 1;
    transform: translateX(0);
    transition: opacity 300ms, transform 300ms;
  }
  .speedx-alert-exit {
    opacity: 1;
  }
  .speedx-alert-exit-active {
    opacity: 0;
    transform: scale(0.9);
    transition: opacity 300ms, transform 300ms;
  }

下面是public.css的内容

html {
  background-color:#f2f2f2;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 18px;
  line-height: 1.667;
  color: #222;
  text-align: justify;
  word-wrap: break-word;
  word-break: break-word;
  -moz-hyphens: auto;
  hyphens: auto;
}

input,
textarea {
  font-family: 'Roboto', sans-serif;
  line-height: 1.4;
  background: #eee;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
  color: #353535d9;
  overflow-wrap: break-word;
}

:not(pre) > code {
  background-color: rgb(214, 214, 214);
  border-radius: 3px;
  padding: 1px 3px;
}

img {
  max-width: 100%;
  max-height: 20em;
}

.page-container {
  position: relative;
  display: flex;
  flex-direction: column;
  background-color:white;
  min-height: 100vh;
}

.layout-content{
  margin: 10px, 0px;
  padding: 0px;
  min-height: 100%;
  flex: 1;
  text-align:justify;
}

.content-wrap {
  padding-bottom: 2.5rem;    /* Footer height */
}

.footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 2.5rem;            /* Footer height */
  padding: 20px 0;
  /* box-shadow: 3px 0 5px #c9c9c9; */
}

blockquote {
  border-left: 2px solid rgb(1, 154, 192);
  margin-left: 0;
  margin-right: 0;
  padding-left: 10px;
  color: rgb(150, 150, 150);
  font-style: italic;
}

blockquote[dir='rtl'] {
  border-left: none;
  padding-left: 0;
  padding-right: 10px;
  border-right: 2px solid #ddd;
}

input {
  box-sizing: border-box;
  font-size: 0.85em;
  width: 100%;
  padding: 0.5em;
  border: 2px solid #ddd;
  background: #fafafa;
}

input:focus {
  outline: 0;
  border-color: blue;
}

iframe {
  width: 100%;
  border: 1px solid #eee;
}

[data-slate-editor] > * + * {
  margin-top: 1em;
}
  
#root{
  display: flex;
  min-height: 100vh;
  flex-direction: column;
  background-color:#f2f2f2;
} 

.alignCenterVH{
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
}

.mainBoxPosition{
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: top;
}

.titleInput {
  display: block;
  width: 100%;
  font-weight: bold;
  min-height: 50px;
  font-size: 22px;
  border:none;
  border-bottom: 1px;
  border-color: rgb(190, 190, 190);
  outline:none;
}

.selectElement {
  display: block;
  max-width: 100%;
  max-height: 20em;
}

.imgsubstring {
  display: block;
  color:rgb(116, 116, 116);
  font-weight: 500;
  font-size: medium;
  padding: 5px;
  text-align: center;
}

.mayi-select {
  width: 400px; height: 200px;line-height: 200px;text-align: center;margin:auto;
  border: 1px solid #ccc;
  background: linear-gradient(#efefef,#ccc) padding-box,
  linear-gradient(135deg, rgba(0, 0, 0, 1) 25%, transparent 25%, transparent 50%, rgba(1, 1, 1, 1) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-size:100% 100%, 8px 8px;
  animation: bg 1s linear infinite;
}

.mayi-select:hover{
  cursor: pointer;
  border: 1px dashed transparent;
}

@keyframes bg {
  0% {
      background-position: 0 0;
  }
  100% {
      background-position: 8px 0;
  }
} 

.alignCenter {
  display: table-cell;
  /*垂直居中 */
  vertical-align: middle;
  /*水平居中*/
  text-align: center;

  /* text-align: center;
	background-color: #fff;
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%,-50%); */
}

.site-layout-background{
  background-color: white;
}

.check-background {
  width: 100px;
  height: 100px;
  background-image: url('data:image/svg+xml,\
  <svg xmlns="http://www.w3.org/2000/svg"\
        width="100" height="100" fill-opacity=".25">\
    <rect x="50" width="50" height="50"></rect>\
    <rect y="50" width="50" height="50"></rect>\
    </svg>');
    background-size:50px 50px;
}

设计一个样式组件,在App中引入一下就可以了,就可以保证我们的所有组件就能够应用到我们的样式。在STheme文件夹中创建 AdapterCss.jsx

import CssBaseline from '@mui/material/CssBaseline';
import '../SCSS/public.css';
import '../SCSS/components.css';
import '../SCSS/bootstrap5.3.0/bootstrap-utilities.min.css';
import '../SCSS/bootstrap5.3.0/bootstrap-grid.min.css';
// import '../SCSS/bootstrap5.3.0/bootstrap.min.css';

export default function AdapterCss() {
  return <CssBaseline />
}

我们只要在根组件中引入一次这个样式适配器就好了。

颜色模式

因为我们要为App适配暗模式,所以在设计之初就要考虑好这个问题。首先,MUI所有的组件就已经适配了两种颜色模式,Bootstrap也是一样。还有一个就是我们自己封装的组件也要适配到暗模式中,就这要求我们自己设计的组件元素应用的颜色模式要么来处MUI, 要么采用Bootstrap,要么我们自己提供一个双模式的颜色体系。也就是说这三种不同框架之间的颜色体系是共存的。下面我们分别来说一说:

MUI的Theme模式

MUI 中提供了两个工具,让我们能构获取和设置颜色模式。

  • ThemeProvider 这个很好理解,就是一个颜色模式厂,就是一个Context;
  • createTheme 创建一个颜色模式。我们这里只是用它来改变MUI的颜色模式;

下面我们用示例说明用法:

import { createTheme } from '@mui/material/styles';

function createMuiTheme(mode) {
    const themeMode = mode === "light" ? "light" : "dark";
    return createTheme({
        palette: {
            mode: themeMode,
        },
    });
}

上面的函数根据我们传入的模式关键字来创建相应的MUI颜色模式。

Bootstrap的颜色模式

这就简单了,我们只要改变顶层包裹组件的data-bs-theme属性值就可以切换颜色模式。

<div data-bs-theme="light"> 这是 light 模式 <div>
  
<div data-bs-theme="dark"> 这是 dark 模式 <div>

很简单吧。

自定义颜色模式

自定义颜色模式就有点技术含量了。也是最繁琐的一环。首先我们要定义的每种颜色要有两个模式下的颜色值。这就要一个标准,由于我没有采用 TS 设计模式,所以就要用其它的办法来约束定义的行为,比如一个函数就是一个很好的办法。

我们在STheme目录中创建一个工具函数库,把所有的我们自定义的工具函数放到其中统一导出就好了。

// SThemeUtils.jsx

import SThemeCodors from "./SColors";

// 生成基本颜色,lightColor为浅色,darkColor为深色
export function sColor(lightColor, darkColor) {
    return {
        light: lightColor,
        dark: darkColor,
    }
}

/**
 * 生成主题模型
 * @param {} mode 
 * @returns 
 */
export default function createSTheme(mode = "light") {
    const themeMode = mode === "light" ? "light" : "dark";
    const sTheme = {mode: themeMode};

    Object.keys(SThemeCodors).forEach(key => {
        sTheme[key] = SThemeCodors[key][themeMode];
    }
    );
    return sTheme;
}

/**
 * 生成MUI系统主题
 * @param {*} mode 
 * @returns 
 */
export function createMuiTheme(mode) {
    const themeMode = mode === "light" ? "light" : "dark";
    return createTheme({
        palette: {
            mode: themeMode,
        },
    });
}
  • 我们通过sColor函数生成一个颜色对象,这样行为就统一了。每个颜色对象中都有一个 light 色 和一个 dark 色。所以我们设计之初就要把每种不同模式下的颜色配置好。这关系到我们整体的App风格。你看,我们设计一个App其实没那么简单对不对,对不同技术技能都要些要求的。
  • createSTheme根据自定义颜色模式生成基于自定义颜色的 theme`

现在就是定义颜色了,在相同的目录下,创建颜色库文件

// sColors.jsx

import { sColor } from "./SThemeUtils";

/**
 * 定义主题颜色模型
 */
const SThemeColors = {
  bgColor: sColor("#edf3f2", "#1D1D1D"), //背景色

  /**
   * 菜单色配置
   */
  badge: sColor("red", "red"), //小红点色
  menuBgcolor: sColor("#EEEEEE", "#0D2745"),//菜单栏的背景色
  hoverMenuBgcolor: sColor("#FFEACC", "#091C32"), //菜单栏背景色Hover

  iconColorNormal: sColor("#1c2322", "#EEEEEE"), //图标色
  iconColorSquare: sColor("#363c3b", "#CCCCCC"), //无图标时的替代色

  menuNomalColor: sColor("#333333", "#07172A"), //菜单栏正常字体色
  activeMenuBgcolor: sColor("#FFEACC", "#1C54AD"), //活动菜单背景色
  activeBorderColor: sColor("#007AFF", "#1C54AD"), //活动菜单边框色

  menuSpliderColor: sColor("#DDDDDD", "#143C6A"), // 菜单栏分隔色

  menuSubitemColor: sColor("#545a59", "#B8B8B8"), //子菜单字体色
  hoverSubitemColor: sColor("#9fa2a1", "#3C628B"), //hover时的子菜单字体色
  hoverMenuSubitemBgcolor: sColor("#FFEACC", "#123862"), //子菜单的hover背景色
  activeMenuSubitemBgcolor: sColor("#FFBF66", "#0E2C4D"),//活动子菜单的背景色

  activeQuickMenuBgcolor: sColor("#FFBF66", "#2266B5"),//活动快捷菜单的子菜单
}

export default SThemeColors;

这就是我们的颜色系统,根据需要自行定义。

创建 ThemeProvider

现在我们向App提供三种 provider, 还要提供 切换 模式的方法,最好的办法当然就是 Context了,我们来设计这几个Provider : 创建 SThemeContext.jsx文件:

// SThemeContext.jsx

import { createContext } from 'react';

/**
 * 创建自定义主题上下文
 */
export const SThemeContext = createContext(null);

export function CusThemeProvider({ theme, children }) {
    return (
        <SThemeContext.Provider value={theme}>
            {
                children
            }
        </SThemeContext.Provider>
    )
}


/**
 * 创建切换主题上下文
 */
export const ToggleSThemeContext = createContext(null);

export function ToggleSThemeProvider({ handler, children }) {
    return (
        <ToggleSThemeContext.Provider value={handler}>
            {
                children
            }
        </ToggleSThemeContext.Provider>
    )
}

/**
 * 创建Bootstrap主题上下文
 * @param {*} param0 
 * @returns 
 */
export function BootstrapThemeProvider({ mode, children }) {
    return (
        <div data-bs-theme={mode}>
            {
                children
            }
        </div>
    )
}

文件里已经备注的很清楚了,就是创建两个上下文就OK了。

现在三种颜色的框架都有了。接下来我们就是要把这三个模式合并成一个Provider就完美了。我们来创建这个文件。在STheme目录下创建 SThemeProvider.jsx文件

// SThemeProvider.jsx

import { useState } from 'react';
import { ThemeProvider } from '@mui/material/styles';
import AdapterCss from './AdapterCss';
import createSTheme, { createMuiTheme } from './SThemeUtils';
import { BootstrapThemeProvider, CusThemeProvider, ToggleSThemeProvider} from './SThemeContext';

/**
 * 项目的皮肤供应器
 * @param {} param0 
 * @returns 
 */
function SThemeProvider({ children }) {  
    const [theme, changeTheme] = useState({ custom: createSTheme("light"), muiTheme: createMuiTheme("light")});
    const toggleThemHandler = () => {
        const muiThemeMode = theme.muiTheme.palette.mode === "light" ? "dark" : "light";
        changeTheme({
            custom: createSTheme(muiThemeMode),
            muiTheme: createMuiTheme(muiThemeMode),
        })
    }

    return (
        <ThemeProvider theme={theme.muiTheme}>
            <CusThemeProvider theme={theme.custom}>
                <BootstrapThemeProvider mode={theme.custom.mode}>
                    <ToggleSThemeProvider handler={toggleThemHandler}>
                        <AdapterCss />
                        {
                            children
                        }
                    </ToggleSThemeProvider>
                </BootstrapThemeProvider>
            </CusThemeProvider>
        </ThemeProvider>
    )
}

export default SThemeProvider;

现在层次很清晰了吧。是不是清爽了许我,这样,我们在根组件中用 SThemeProvider包裹就好了。是不是很优雅。我们只需要在项目入口文件 main.jsx 中这样写就行了。

import React from 'react'
import ReactDOM from 'react-dom/client'
import SThemeProvider from './SMenu/STheme/SThemeProvider.jsx';
import App from './SMenu/App.jsx';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <SThemeProvider>
      <App />
    </SThemeProvider>
  </React.StrictMode>,
)

编写主题切换Hook

这是主题最后一个环节,我们要提供一个 Hook 供我们的组件使用,要不然,设计主题有什么意义呢。

在 STheme目录中创建 文件 useToggleThemeHook.jsx

import { useContext } from 'react';
import { ToggleSThemeContext } from './SThemeContext';

// 获取切换主题的功能函数。
const useToggleTheme = () => {
    return useContext(ToggleSThemeContext)
}

export default useToggleTheme;

是不是太完美了。 是相当的完美啊。(未完待续)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1431775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp使用u-popup组件弹窗出现页面还可滑动

*1、问题所在&#xff1a; 弹窗遮罩层出现了页面依旧可以上下滑动 2、要求: 为了用户更好交互体验&#xff0c;弹窗出现后应禁止页面往下滑动 3、实现思路&#xff1a; 在弹窗盒子外层添加个阻止触摸冒泡事件&#xff0c;使用touchmove.stop.prevent 4、代码如下&#xff…

Android简单支持项目符号的EditText

一、背景及样式效果 因项目需要&#xff0c;需要文本编辑时&#xff0c;支持项目符号&#xff08;无序列表&#xff09;尝试了BulletSpan&#xff0c;但不是很理想&#xff0c;并且考虑到影响老版本回显等因素&#xff0c;最终决定自定义一个BulletEditText。 先看效果&…

【深度学习】讲透深度学习第3篇:TensorFlow张量操作(代码文档已分享)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论深度学习相关知识。可以让大家熟练掌握机器学习基础,如分类、回归&#xff08;含代码&#xff09;&#xff0c;熟练掌握numpy,pandas,sklearn等框架使用。在算法上&#xff0c;掌握神经网络的数学原理&#xff0c;手动实…

vue + 动态加载图片

首先尝试我们经常用的require动态引入&#xff0c; 发现报错&#xff1a;require is not defind&#xff0c;这是因为 require 属于 Webpack 的方法&#xff0c;我现在的环境是 vue3.0 vite 1、 适用于处理少量链接的资源文件 import img from ./img.png; <img :src"…

Linux挂载本地ISO镜像源

1 创建挂载镜像的目录 mkdir /opt/rpm2 上传iso镜像到root目录 3 挂载镜像 mount -t iso9660 /root/CentOS-7-x86_64-DVD-2207-02.iso /opt/rpm/ 4 若是ftp文件夹挂载本地 mkdir /opt/iso 将ftp上software/caozuoxitong目录挂载到本地/opt/iso/ 目录 mount -t cifs //172.…

字符串左旋

题目&#xff1a;字符串左旋 内容&#xff1a;实现一个函数&#xff0c;可以左旋字符串中的K个字符。 例如&#xff1a; ABCDEF左旋一个字符可以得到BCDEFA ABCDEF左旋两个字符可以得到CDEFAB 方法一&#xff1a;移动字符 #include <stdio.h> #include <string.h>c…

深入分析AOP+自定义注解+RBAC实现操作权限管理设计思想

深入分析AOP自定义注解RBAC实现操作权限管理设计思想&#xff01;经过三个小节的部署&#xff0c;我们已经把这个思想走了一遍。下面内容是对于此次设计思想的一个详细介绍。帮助大家完善透彻的了解&#xff0c;到底自定义注解是如何实现的。以及&#xff0c;权限管理的核心思想…

程序报错无法打开源文件stdafx.h

在运行代码时&#xff0c;代码中头文件突然报错程序无法打开源文件stdafx.h include “stdafx.h”,编译器就说无法打开源文件&#xff0c;直接上干货解决方法是&#xff1a; 1.打开项目 ->项目属性&#xff08;最后一个&#xff09;-> C/C ->常规&#xff0c; 2在附…

音频几个相关概念及心理声学模型

系列文章目录 音频格式的介绍文章系列&#xff1a; 音频编解码格式介绍&#xff1a;音频几个相关概念及心理声学模型 https://blog.csdn.net/littlezls/article/details/135499627 音频编解码格式介绍&#xff1a;音频编码格式介绍 https://blog.csdn.net/littlezls/article/d…

nohost本地部署

1、安装node Node.js 官方网站下载&#xff1a;https://nodejs.org/en/download/ 2、安装whistle 安装命令为 npm install -g whistle 或 npm install -g cnpm --registryhttps://registry.npm.taobao.org 后&#xff0c;使用 cnpm install -g whistle 来安装 3、插件修改 官方…

【漏洞库】O2OA系统

O2OA invoke 后台远程命令执行漏洞 CNVD-2020-18740 漏洞描述 O2OA是一款开源免费的企业及团队办公平台&#xff0c;提供门户管理、流程管理、信息管理、数据管理四大平台,集工作汇报、项目协作、移动OA、文档分享、流程审批、数据协作等众多功能&#xff0c;满足企业各类管理…

JavaSE-项目小结-IP归属地查询(本地IP地址库)

一、项目介绍 1. 背景 IP地址是网络通信中的重要标识&#xff0c;通过分析IP地址的归属地信息&#xff0c;可以帮助我们了解访问来源、用户行为和网络安全等关键信息。例如应用于网站访问日志分析&#xff1a;通过分析访问日志中的IP地址&#xff0c;了解网站访问者的地理位置分…

【Docker】Docker Registry(镜像仓库)

文章目录 一、什么是 Docker Registry二、镜像仓库分类三、镜像仓库工作机制四、常用的镜像仓库五、常用命令镜像仓库命令镜像命令(部分)容器命令(部分) 六、docker镜像仓库实战综合实战一&#xff1a;搭建一个 nginx 服务综合实战二&#xff1a;Docker hub上创建自己私有仓库综…

使用maven对springboot项目进行瘦身

目录 一、什么是Maven 二、springboot 项目 三、springboot 项目瘦身 一、什么是Maven Maven是一个基于Java的项目管理和构建工具。它通过提供一个一致的项目结构、自动化构建脚本和依赖管理系统&#xff0c;简化了Java项目的构建过程。 Maven使用一种称为POM&#xff08;…

CentOS7局域网内搭建本地yum源

CentOS7.6 局域网内搭建本地yum源 一、背景 客户机房服务器无法直连公网&#xff0c;远程通过堡垒机部署环境&#xff0c;因为机器比较多&#xff0c;最终选择通过安装自定义yum源进行部署。以下为自己部署yum源过程&#xff0c;以备后续使用。 二、准备yum源Packages 网上…

如何以管理员身份删除node_modules文件

今天拉项目&#xff0c;然后需要安装依赖&#xff0c;但是一直报错&#xff0c;如下&#xff1a; 去搜这个问题会让把node_modules文件先删掉 再去安装依赖。我在删除的过程中会说请以管理员身份来删除。 那么windows如何以管理员身份删除node_modules文件呢&#xff1f; wi…

impala与kudu进行集成

文章目录 概要Kudu与Impala整合配置Impala内部表Impala外部表Impala sql操作kuduImpala jdbc操作表如果使用了Hadoop 使用了Kerberos认证&#xff0c;可使用如下方式进行连接。 概要 Impala是一个开源的高效率的SQL查询引擎&#xff0c;用于查询存储在Hadoop分布式文件系统&am…

性能篇:如何解决高并发下 I/O瓶颈?

大家好,我是小米!今天我们来聊一个在高并发场景下经常遇到的挑战,那就是I/O瓶颈。随着互联网的快速发展,我们的应用在处理海量数据时,I/O操作成为了一个极为关键的环节。那么,问题来了,什么是I/O呢? 什么是I/O I/O(Input/Output)是计算机系统中一个至关重要的概念,…

python+pytest接口自动化 —— 参数关联

整理了一些软件测试方面的资料、面试资料&#xff08;接口自动化、web自动化、app自动化、性能安全、测试开发等&#xff09;&#xff0c;有需要的小伙伴可以文末关注我的文末公众号或者进软件交流群&#xff0c;无套路自行领取~ 什么是参数关联&#xff1f; 参数关联&#…

Java语法学习坐标体系/绘图

Java语法学习坐标体系/绘图 大纲 基本介绍绘图 具体案例 1. 基本介绍 2.绘图 基本介绍&#xff1a; 注意每次自动调用&#xff0c;就会重新执行一次paint方法里的所有程序 先自定义面板 创建一个类继承JPanel&#xff0c;然后重写构造器&#xff0c;paint方法 class M…