【React】入门Day04 —— 项目搭建及登录与表单校验、token 管理、路由鉴权实现

news2024/10/5 0:31:10

项目搭建

  • 创建项目

    # 使用npx创建项目
    npx create-react-app my-react-app
    # 进入项目目录
    cd my-react-app
    # 创建项目目录结构
    mkdir -p src/{apis,assets,components,pages,store,utils}
    touch src/{App.js,index.css,index.js}
    • 使用npx create-react-app创建项目,进入项目目录后通过npm start启动。
    • 调整项目目录结构,包括apisassetscomponentspages等多个文件夹。
  • 使用技术

    • 接入scss预处理器,安装sass工具,创建全局样式文件index.scss
      # 安装sass工具
      npm i sass -D
      // 在src/index.scss中设置全局样式
      body {
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
      }
    • 引入组件库antd,安装后在Login页面测试Button组件。
      # 安装antd组件库
      npm i antd
      // 在src/pages/Login/index.jsx中使用Button组件
      import React from 'react';
      import { Button } from 'antd';
      
      const Login = () => {
        return (
          <div>
            <Button type='primary'>登录</Button>
          </div>
        );
      };
      
      export default Login;
    • 使用react-router-dom配置基础路由,创建LayoutLogin组件并配置路由规则。
      # 安装react-router-dom
      npm i react-router-dom
      // 在src/router/index.js中配置路由
      import { createBrowserRouter } from 'react-router-dom';
      import Login from '../pages/Login';
      import Layout from '../pages/Layout';
      
      const router = createBrowserRouter([
        {
          path: '/',
          element: <Layout />,
        },
        {
          path: '/login',
          element: <Login />,
        },
      ]);
      
      export default router;
    • 通过craco工具包配置别名路径,在craco.config.js中设置webpack别名,并在jsconfig.json中配置VsCode提示。
      # 安装craco工具包
      npm i @craco/craco -D
      // 在craco.config.js中配置别名
      const path = require('path');
      module.exports = {
        webpack: {
          alias: {
            '@': path.resolve(__dirname,'src')
          }
        }
      };
      // 在package.json中修改scripts命令
      "scripts": {
        "start": "craco start",
        "build": "craco build",
        "test": "craco test",
        "eject": "react-scripts eject"
      }
      // 在src/router/index.js中使用别名
      import { createBrowserRouter } from 'react-router-dom';
      import Login from '@/pages/Login';
      import Layout from '@/pages/Layout';
      
      const router = createBrowserRouter([
        {
          path: '/',
          element: <Layout />,
        },
        {
          path: '/login',
          element: <Login />,
        },
      ]);
      
      export default router;
      // 在jsconfig.json中配置VsCode提示
      {
        "compilerOptions": {
          "baseUrl": "./",
          "paths": {
            "@/*": ["src/*"]
          }
        }
      }

  • 功能模块实现

    • 登录模块

      • 基本结构搭建

  •         在Login/index.js创建登录页面结构,引入antd组件,使用@/assets路径引入图片,在Login/index.scss中设置样式。
  • import React from 'react';
    import { Card, Form, Input, Button } from 'antd';
    import logo from '@/assets/logo.png';
    import './index.scss';
    
    const Login = () => {
      return (
        <div className="login">
          <Card className="login-container">
            <img className="login-logo" src={logo} alt="" />
            <Form>
              <Form.Item>
                <Input size="large" placeholder="请输入手机号" />
              </Form.Item>
              <Form.Item>
                <Input size="large" placeholder="请输入验证码" />
              </Form.Item>
              <Form.Item>
                <Button type="primary" htmlType="submit" size="large" block>
                  登录
                </Button>
              </Form.Item>
            </Form>
          </Card>
        </div>
      );
    };
    
    export default Login;
  • 表单校验实现

    • Form组件设置validateTrigger,为Form.Item组件设置namerules属性进行表单校验。
      import React from 'react';
      import { Form, Input, Button } from 'antd';
      
      const Login = () => {
        return (
          <Form validateTrigger={['onBlur']}>
            <Form.Item
              name="mobile"
              rules={[
                { required: true, message: '请输入手机号' },
                {
                  pattern: /^1[3-9]\d{9}$/,
                  message: '手机号码格式不对'
                }
              ]}
            >
              <Input size="large" placeholder="请输入手机号" />
            </Form.Item>
            <Form.Item
              name="code"
              rules={[
                { required: true, message: '请输入验证码' },
              ]}
            >
              <Input size="large" placeholder="请输入验证码" maxLength={6} />
            </Form.Item>
            <Form.Item>
              <Button type="primary" htmlType="submit" size="large" block>
                登录
              </Button>
            </Form.Item>
          </Form>
        );
      };
      
      export default Login;
  • 获取登录表单数据

    • Form组件设置onFinish属性,在点击登录按钮时触发获取表单数据的函数。
      import React from 'react';
      import { Form, Input, Button } from 'antd';
      
      const Login = () => {
        const onFinish = formValue => {
          console.log(formValue);
        };
      
        return (
          <Form onFinish={onFinish}>
            <Form.Item>
              <Input size="large" placeholder="请输入手机号" />
            </Form.Item>
            <Form.Item>
              <Input size="large" placeholder="请输入验证码" />
            </Form.Item>
            <Form.Item>
              <Button type="primary" htmlType="submit" size="large" block>
                登录
              </Button>
            </Form.Item>
          </Form>
        );
      };
      
      export default Login;
  • 封装 request 工具模块

    • 安装axios,在utils/request.js中创建axios实例,配置baseURL、请求拦截器和响应拦截器。
      # 安装axios
      npm i axios
      import axios from 'axios';
      
      const http = axios.create({
        baseURL: 'http://example.com/api',
        timeout: 5000
      });
      
      // 请求拦截器
      http.interceptors.request.use(config => {
        return config;
      }, error => {
        return Promise.reject(error);
      });
      
      // 响应拦截器
      http.interceptors.response.use(response => {
        return response.data;
      }, error => {
        return Promise.reject(error);
      });
      
      export { http };
  • 使用 Redux 管理 token

    • 安装react-redux@reduxjs/toolkit,在store中创建userStore切片,设置token初始状态和setUserInforeducers,封装fetchLogin异步方法。
      # 安装react-redux和@reduxjs/toolkit
      npm i react-redux @reduxjs/toolkit
      import { createSlice } from '@reduxjs/toolkit';
      import { http } from '@/utils';
      
      const userStore = createSlice({
        name: 'user',
        initialState: {
          token: ''
        },
        reducers: {
          setUserInfo(state, action) {
            state.token = action.payload;
          }
        }
      });
      
      const { setUserInfo } = userStore.actions;
      const userReducer = userStore.reducer;
      
      const fetchLogin = loginForm => {
        return async dispatch => {
          const res = await http.post('/authorizations', loginForm);
          dispatch(setUserInfo(res.data.token));
        };
      };
      
      export { fetchLogin };
      export default userReducer;
  • 实现登录逻辑

    • Login组件中调用fetchLogin方法,登录成功后跳转到首页并提示。
      import React from 'react';
      import { message } from 'antd';
      import { useDispatch } from 'react-redux';
      import { fetchLogin } from '@/store/modules/user';
      
      const Login = () => {
        const dispatch = useDispatch();
      
        const onFinish = async formValue => {
          await dispatch(fetchLogin(formValue));
          message.success('登录成功');
        };
      
        return (
          <div>
            <form onSubmit={onFinish}>
              {/* 登录表单字段 */}
            </form>
          </div>
        );
      };
      
      export default Login;
  • token 持久化

    • 封装setTokengetTokenclearToken方法,在userStoresetUserInfo时将token存入本地。
      // 在@/utils/token.js中封装存取方法
      const TOKENKEY = 'token_key';
      
      function setToken(token) {
        return localStorage.setItem(TOKENKEY, token);
      }
      
      function getToken() {
        return localStorage.getItem(TOKENKEY);
      }
      
      function clearToken() {
        return localStorage.removeItem(TOKENKEY);
      }
      
      export {
        setToken,
        getToken,
        clearToken
      };
      // 在userStore中使用token持久化方法
      import { createSlice } from '@reduxjs/toolkit';
      import { http } from '@/utils';
      import { getToken, setToken } from '@/utils/token';
      
      const userStore = createSlice({
        name: 'user',
        initialState: {
          token: getToken() || ''
        },
        reducers: {
          setUserInfo(state, action) {
            state.token = action.payload;
            setToken(state.token);
          }
        }
      });
      
      export default userStore;
  • 请求拦截器注入 token

    • request.js的请求拦截器中,判断是否有token,有则添加到请求头Authorization中。
      // 在utils/request.js中注入token
      import axios from 'axios';
      
      const http = axios.create({
        baseURL: 'http://example.com/api',
        timeout: 5000
      });
      
      http.interceptors.request.use(config => {
        const token = getToken();
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      }, error => {
        return Promise.reject(error);
      });
      
      http.interceptors.response.use(response => {
        return response.data;
      }, error => {
        return Promise.reject(error);
      });
      
      export { http };
  • 路由鉴权实现

    • components/AuthRoute/index.jsx中创建路由鉴权高阶组件,判断本地是否有token,决定是否重定向到登录页面。
      import React from 'react';
      import { Navigate } from 'react-router-dom';
      import { getToken } from '@/utils';
      
      const AuthRoute = ({ children }) => {
        const isToken = getToken();
        if (isToken) {
          return <>{children}</>;
        } else {
          return <Navigate to="/login" replace />;
        }
      };
      
      export default AuthRoute;
      // 在src/router/index.js中使用AuthRoute组件
      import { createBrowserRouter } from 'react-router-dom';
      import Login from '@/pages/Login';
      import Layout from '@/pages/Layout';
      import AuthRoute from '@/components/AuthRoute';
      
      const router = createBrowserRouter([
        {
          path: '/',
          element: <AuthRoute><Layout /></AuthRoute>,
        },
        {
          path: '/login',
          element: <Login />,
        },
      ]);
      
      export default router;
  • Layout 模块

    • 基本结构和样式 reset

      • pages/Layout/index.js中使用antd/Layout组件创建页面结构,引入antdMenuPopconfirm等组件,设置样式并安装normalize.css进行样式 reset。
        import React from 'react';
        import { Layout, Menu, Popconfirm } from 'antd';
        import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';
        import './index.scss';
        import 'normalize.css';
        
        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">用户名</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;
    • 二级路由配置

      • pages目录创建HomeArticlePublish页面文件夹,在router/index.js中配置嵌套子路由,在Layout中配置二级路由出口,使用Link修改左侧菜单内容实现路由切换。
        // 在pages目录创建Home.jsx
        import React from 'react';
        
        const Home = () => {
          return <div>首页内容</div>;
        };
        
        export default Home;
        // 在pages目录创建Article.jsx
        import React from 'react';
        
        const Article = () => {
          return <div>文章管理内容</div>;
        };
        
        export default Article;
        // 在pages目录创建Publish.jsx
        import React from 'react';
        
        const Publish = () => {
          return <div>发布文章内容</div>;
        };
        
        export default Publish;
        // 在src/router/index.js中配置二级路由
        import { createBrowserRouter } from 'react-router-dom';
        import Login from '@/pages/Login';
        import Layout from '@/pages/Layout';
        import Publish from '@/pages/Publish';
        import Article from '@/pages/Article';
        import Home from '@/pages/Home';
        import { AuthRoute } from '@/components/AuthRoute';
        
        const router = createBrowserRouter([
          {
            path: '/',
            element: (
              <AuthRoute>
                <Layout />
              </AuthRoute>
            ),
            children: [
              {
                index: true,
                element: <Home />,
              },
              {
                path: 'article',
                element: <Article />,
              },
              {
                path: 'publish',
                element: <Publish />,
              },
            ],
          },
          {
            path: '/login',
            element: <Login />,
          },
        ]);
        
        export default router;
        // 在Layout组件中配置二级路由出口
        import React from 'react';
        import { Outlet } from 'react-router-dom';
        
        const GeekLayout = () => {
          return (
            <Layout className="layout-content" style={{ padding: 20 }}>
              <Outlet />
            </Layout>
          );
        };
        
        export default GeekLayout;
    • 路由菜单点击交互实现

      • Menu组件设置onClick属性实现点击菜单跳转路由,通过useLocation获取当前路由路径实现菜单反向高亮。
        import React from 'react';
        import { Outlet, useNavigate } from 'react-router-dom';
        import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';
        
        const items = [
          {
            label: '首页',
            key: '/',
            icon: <HomeOutlined />,
          },
          {
            label: '文章管理',
            key: '/article',
            icon: <DiffOutlined />,
          },
          {
            label: '创建文章',
            key: '/publish',
            icon: <EditOutlined />,
          },
        ];
        
        const GeekLayout = () => {
          const navigate = useNavigate();
        
          const menuClick = route => {
            navigate(route.key);
          };
        
          return (
            <Layout>
              <Header className="main-header">
                <div className="logo" />
                <div className="user-info">
                  <span className="user-name">用户名</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"
                    selectedKeys={['1']}
                    items={items}
                    style={{ height: '100%', borderRight: 0 }}
                    onClick={menuClick}
                  ></Menu>
                </Sider>
                <Layout className="layout-content" style={{ padding: 20 }}>
                  <Outlet />
                </Layout>
              </Layout>
            );
        };
        
        export default GeekLayout;
        // 菜单反向高亮实现
        import React from 'react';
        import { Outlet, useLocation } from 'react-router-dom';
        import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';
        
        const items = [
          {
            label: '首页',
            key: '/',
            icon: <HomeOutlined />,
          },
          {
            label: '文章管理',
            key: '/article',
            icon: <DiffOutlined />,
          },
          {
            label: '创建文章',
            key: '/publish',
            icon: <EditOutlined />,
          },
        ];
        
        const GeekLayout = () => {
          const location = useLocation();
          const selectedKey = location.pathname;
        
          return (
            <Layout>
              <Header className="main-header">
                <div className
    • 展示个人信息

      • store/userStore.js中编写获取用户信息的逻辑,在Layout组件中触发fetchUserInfo方法获取信息并渲染用户名。
        // store/userStore.js
        import { createSlice } from '@reduxjs/toolkit';
        import { http } from '@/utils';
        import { getToken, setToken } from '@/utils';
        
        const userStore = createSlice({
          name: 'user',
          initialState: {
            token: getToken() || '',
            userInfo: {}
          },
          reducers: {
            setUserToken(state, action) {
              state.token = action.payload;
              setToken(state.token);
            },
            setUserInfo(state, action) {
              state.userInfo = action.payload;
            },
            clearUserInfo(state) {
              state.token = '';
              state.userInfo = {};
              clearToken();
            }
          }
        });
        
        // 解构出actionCreater
        const { setUserToken, setUserInfo, clearUserInfo } = userStore.actions;
        // 获取reducer函数
        const userReducer = userStore.reducer;
        
        const fetchLogin = (loginForm) => {
          return async (dispatch) => {
            const res = await http.post('/authorizations', loginForm);
            dispatch(setUserToken(res.data.token));
          };
        };
        
        const fetchUserInfo = () => {
          return async (dispatch) => {
            const res = await http.get('/user/profile');
            dispatch(setUserInfo(res.data));
          };
        };
        
        export { fetchLogin, fetchUserInfo, clearUserInfo };
        export default userReducer;
    • 退出登录实现

      • Popconfirm添加确认回调事件,在store/userStore.js中新增clearUserInfo方法删除token和用户信息,在回调事件中调用该方法并返回登录页面。
        // pages/Layout/index.js
        import React, { useEffect } from 'react';
        import { Layout, Menu, Popconfirm } from 'antd';
        import {
          HomeOutlined,
          DiffOutlined,
          EditOutlined,
          LogoutOutlined,
        } from '@ant-design/icons';
        import { useDispatch, useSelector } from 'react-redux';
        import { fetchUserInfo } from '@/store/modules/user';
        
        const { Header, Sider } = Layout;
        
        const items = [
          // 菜单配置项
        ];
        
        const GeekLayout = () => {
          const dispatch = useDispatch();
          const name = useSelector(state => state.user.userInfo.name);
        
          useEffect(() => {
            dispatch(fetchUserInfo());
          }, [dispatch]);
        
          const loginOut = () => {
            dispatch(clearUserInfo());
            // 假设这里有合适的导航函数,替换为实际的导航逻辑
            // navigate('/login'); 
          };
        
          return (
            <Layout>
              <Header className="header">
                <div className="logo" />
                <div className="user-info">
                  <span className="user-name">{name}</span>
                  <span className="user-logout">
                    <Popconfirm
                      title="是否确认退出?"
                      okText="退出"
                      cancelText="取消"
                      onConfirm={loginOut}
                    >
                      <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;
    • 处理 Token 失效

      • http.interceptors.response中判断响应状态码为401时,清除token,跳转到登录页面并刷新页面。
        // 在http.js(假设是配置axios请求相关的文件)中处理Token失效
        import axios from 'axios';
        
        const http = axios.create({
          baseURL: 'http://example.com/api',
          timeout: 5000
        });
        
        http.interceptors.response.use((response) => {
          return response.data;
        }, (error) => {
          if (error.response && error.response.status === 401) {
            // 假设这里有合适的获取和清除token的函数,替换为实际的逻辑
            const token = getToken();
            if (token) {
              clearToken();
            }
            // 假设这里有合适的导航函数,替换为实际的导航逻辑
            // navigate('/login'); 
            window.location.reload();
          }
          return Promise.reject(error);
        });
        
        export { http };

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

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

相关文章

深入浅出,从源码搞清Bean的加载过程

深入浅出&#xff0c;从源码搞清Bean的加载过程 前言 Bean的加载过程算是面试中的老生常谈了&#xff0c;今天我们就来从源码层面深入去了解一下Spring中是如何进行Bean的加载的 Spring 先看示例代码&#xff1a; public static void main(String[] args) {ApplicationCon…

微服务之间的相互调用的几种常见实现方式对比

目录 微服务之间的相互调用的几种实现方式 一、HTTP HTTP/RESTful API调用工作原理 二、RPC 设计理念与实现方式 协议与传输层 RPC远程调用工作原理 应用场景与性能考量 特点 三、Feign 设计理念与实现方式 协议与传输层 Feign调用的基本流程 Feign调用的工作原理…

算法训练营打卡Day19

目录 1.二叉搜索树的最近公共祖先 2.二叉树中的插入操作 3.删除二叉搜索树中的节点 题目1、二叉搜索树的最近公共祖先 力扣题目链接(opens new window) 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有…

温度转换-C语言

1.问题&#xff1a; 输入一个华氏温度&#xff0c;要求输出摄氏温度。公式为 c5(F-32)/9&#xff0c;取位2小数。 2.解答&#xff1a; scanf("%lf",&f);或者scanf("%f",&f);如果你前面定义的f是用double类型的话&#xff0c;就应该用%lf格式&…

deploy thingsboard

ThingsBoard部署 平台&#xff1a;windows10&#xff0c;idea2022&#xff0c;postgres15 maven仓库 进入thingsboard源码下载目录: 主要执行以下两个命令&#xff1a; mvn编译&#xff1a; mvn clean install -Dmaven.test.skiptrue编译报错时&#xff1a; 清除java进程 t…

计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

UART通信—基于江科大源码基础进行的改进和解析

我就不讲理论了&#xff0c;CSDN上大佬属实多&#xff0c;我就只讲代码了&#xff0c;串口的基本理论&#xff0c;大家去看其他大佬写的吧 一、源文件的组成 1、包含的头文件 stm32f10x.h 是STM32F10x系列微控制器的标准外设库&#xff08;Standard Peripheral Library&…

C语言基础(7)之操作符(1)(详解)

目录 1. 各种操作符介绍 1.1 操作符汇总表 2. 移位操作符 2.1 移位操作符知识拓展 —— 原码、反码、补码 2.2 移位操作符讲解 2.2.1 右移操作符 ( >> ) 2.2.2 左移操作符 ( << ) 3. 位操作符 3.1 & (按位与) 3.2 | (按位或) 3.3 ^ (按位异或) 3.4…

【AI学习】Mamba学习(二):线性注意力

上一篇《Mamba学习&#xff08;一&#xff09;&#xff1a;总体架构》提到&#xff0c;Transformer 模型的主要缺点是&#xff1a;自注意力机制的计算量会随着上下文长度的增加呈平方级增长。所以&#xff0c;许多次二次时间架构&#xff08;指一个函数或算法的增长速度小于二次…

C++ 多态:重塑编程效率与灵活性

目录 多态的概念 多态的定义及实现 多态的构成条件 虚函数 虚函数的重写 虚函数重写的两个例外&#xff1a; 1. 协变(基类与派生类虚函数返回值类型不同) 2. 析构函数的重写(基类与派生类析构函数的名字不同&#xff09; 析构函数要不要定义成虚函数&#xff1f;&…

绝对值得收藏!分享7款ai写作论文免费一键生成网站

在当前的学术研究和写作过程中&#xff0c;AI写作工具已经成为了许多研究者和学生的重要助手。这些工具不仅能够提高写作效率&#xff0c;还能帮助生成高质量的论文内容。以下是七款免费的AI写作论文生成器&#xff0c;其中特别推荐千笔-AIPassPaper。 1.千笔-AIPassPaper 千…

信号处理: Block Pending Handler 与 SIGKILL/SIGSTOP 实验

1. 信号处理机制的 “三张表” kill -l &#xff1a;前 31 个信号为系统标准信号。 block pending handler 三张表保存在每个进程的进程控制块 —— pcb 中&#xff0c;它们分别对应了某一信号的阻塞状态、待处理状态以及处理方式。 block &#xff1a;通过 sigset_t 类型实现&…

YOLO11改进 | 检测头 | 融合渐进特征金字塔的检测头【AFPN3】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文介绍了一个渐进特征金字塔网络&…

关于 S7 - 1200 通过存储卡进行程序更新

西门子S7-1200系列PLC可以通过存储卡进行程序的更新&#xff0c;固件版本的升级以及程序数据的存储多项功能。本例进行程序更新的操作。 存储卡的订货号以及存储容量 一&#xff1b;如何插入存储卡 在CPU断电下&#xff0c;将CPU上挡板向下掀开&#xff0c;可以看到右上角有一…

ai写作论文会被检测吗?分享市面上7款自动写论文网站

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI写作工具在学术界引起了广泛关注。然而&#xff0c;这些工具的使用也引发了关于学术诚信和检测机制的讨论。根据多所高校的声明&#xff0c;为了应对AI代写论文的现象&#xff0c;许多高校已经开始引入论文检测工具…

Python入门:深入了解__init__.py 文件(如何实现动态导入子模块)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 `__init__.py` 的作用示例:📝 如何编写 `__init__.py`1. 空的 `__init__.py`2. 导入子模块3. 初始化代码4. 动态导入子模块📝 编写 `__init__.py` 的技巧和注意事项⚓️ 相关链接 ⚓️📖 介绍 📖 在…

01:(寄存器开发)点亮一个LED灯

寄存器开发 1、单片机的简介1.1、什么是单片机1.2、F1系列内核和芯片的系统架构1.3、存储器映像1.4、什么是寄存器 2、寄存器开发模板工程3、使用寄存器点亮一个LED4、代码改进15、代码改进2 本教程使用的是STM32F103C8T6最小系统板&#xff0c;教程来源B站up“嵌入式那些事”。…

前缀和(6)_和可被k整除的子数组_蓝桥杯

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 前缀和(6)_和可被k整除的子数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

kubeadm部署k8s

1.1 安装Docker [rootk8s-all ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo [rootk8s-all ~]# sed -i sdownload.docker.commirrors.huaweicloud.com/docker-ce /etc/yum.repos.d/docker-ce.repo [ro…