Vue3 路由权限管理:基于角色的路由生成与访问控制

news2025/4/8 10:14:41

Vue3 路由权限管理:基于角色的路由生成与访问控制

一、核心概念

1.1 大致流程思路:

用户在登录完成的时候,后端给出一个此登录用户对应的角色名字,此时可以将这个用户的角色存起来(vuex/pinia)中,在设置路由时的meta字段中设置的roles属性如:roles: ['admin', 'accountA', 'accountB']----这就是每个页面能访问的角色名。至此为止,用户的角色名字我们拿到了,每个页面能访问的角色名字我们也知道了,接下来只需要去判断当前用户的角色名是否包含这些权限即可—这就需要交给导航守卫了:router.beforeEach((to, from, next) => {})

1.2 核心组件对比表

组件作用示例特点
静态路由基础公共路由登录页/404页无需权限,初始加载
动态路由权限控制路由管理后台各页面按需加载,角色过滤
路由守卫访问控制beforeEach钩子实时验证,安全屏障
状态管理角色存储Vuex/Pinia全局共享,持久化

基于角色的路由权限管理系统主要包含以下几个核心部分:

  1. 静态路由:无需权限即可访问的路由(如登录页、404页)

  2. 动态路由:需要根据角色的权限进行控制是否显示的路由(如后台管理页面)。

  3. 角色权限配置:定义哪些角色可以访问哪些路由,如:

在这里插入图片描述

  1. 路由守卫:在路由跳转时进行权限验证

二、代码实现解析

1. 路由配置

// 静态路由 - 无需权限
const staticRoutes = [
  {
    path: '/login',
    name: 'Login',
    component: LoginView
  },
  {
    path: '/404',
    name: 'NotFound',
    component: NotFoundView
  }
];

// 动态路由 - 要根据角色的权限进行显示
export const dynamicRoutes = [
  {
    path: '/admin',
    name: 'admin',
    component: HomeView,
    meta: {
      title: "首页",
      title_path: '/admin',
      sub_title: "后台管理",
      roles: ['admin', 'accountA', 'accountB'] // 修正为数组格式
    },
    children: [
      {
        path: 'user',
        name: 'user',
        component: UserView,
        meta: {
          title: "用户管理",
          title_path: '/admin/user',
          sub_title: "用户信息编辑",
          roles: ['admin', 'accountA', 'accountB'] // 修正为数组格式
        }
      },
      {
        path: 'role',
        name: 'role',
        component: RoleView,
        meta: {
          title: "角色管理",
          title_path: '/admin/role',
          sub_title: "角色信息编辑",
          roles: ['admin', 'accountA'] // 修正为数组格式
        }
      },
      {
        path: 'permis',
        name: 'permis',
        component: PermissView,
        meta: {
          title: "权限管理",
          title_path: '/admin/permis',
          sub_title: "权限信息编辑",
          roles: ['admin'] // 修正为数组格式
        }
      }
    ]
  }
]

2. 路由初始化

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes: staticRoutes // 初始只加载静态路由
})

3. 动态路由添加

在用户登录后,根据角色动态添加路由:

// 过滤出用户有权限访问的路由
function filterRoutes(routes: RouteRecordRaw[], userRoles: string[]) {
  return routes.filter(route => {
    // 如果没有设置roles,则默认允许访问
    if (!route.meta?.roles) return true
    
    // 检查用户是否有任一所需角色
    return route.meta.roles.some(role => userRoles.includes(role))
  })
}

// 添加动态路由
function addDynamicRoutes(userRoles: string[]) {
  const accessibleRoutes = filterRoutes(dynamicRoutes, userRoles)
  
  // 先移除可能已存在的动态路由
  router.getRoutes().forEach(route => {
    if (dynamicRoutes.some(dr => dr.name === route.name)) {
      router.removeRoute(route.name!)
    }
  })
  
  // 添加新路由
  accessibleRoutes.forEach(route => {
    router.addRoute(route)
  })
}

4. 路由守卫实现

router.beforeEach((to, from, next) => {
  const store = useStore()
  const userRoles = store.state.roles || []
  
  // 1. 检查是否需要权限
  if (to.meta.roles) {
    const requiredRoles = to.meta.roles
    const hasPermission = requiredRoles.some(role => 
      userRoles.includes(role)
    )
    
    if (!hasPermission) {
      return next('/404') // 无权限跳转404
    }
  }
  
  // 2. 检查是否已登录但访问登录页
  if (to.name === 'Login' && store.state.token) {
    return next('/admin') // 已登录用户跳转首页
  }
  
  next()
})

三、完整工作流程

  1. 应用初始化
    • 只加载静态路由(登录页、404页)
    • 用户访问时首先进入登录页

  2. 用户登录

    vuex:store/index.ts :

    import { createStore } from 'vuex'
    
    export default createStore({
      state: {
        roles: [],
      },
      getters: {
        getRoles: state => state.roles // 添加一个getter来获取roles
      },
      mutations: {
        SET_ROLES(state, roles) { // 添加mutation来修改roles
          state.roles = roles
        }
      },
      actions: {
        setRoles({ commit }, roles) { // 正确的action写法
          commit('SET_ROLES', roles) // 通过commit调用mutation
        }
      },
      modules: {
      }
    })
    

    view/LoginView.vue :

    import { dynamicRoutes } from '@/router'; // 导入动态路由
    // 检查当前用户角色的操作---可以放在一个js文件中导入。这里直接写入这个文件
    function filterRoutesByRole(routes: any[], userRoles: string[]) {
      return routes.filter((route) => {
        // 如果没有设置roles,或者用户角色包含任一所需角色
        return (
          !route.meta?.roles ||
          route.meta.roles.some((role: string) => userRoles.includes(role))
        );
      });
    }
    function generateDynamicRoutes() {
      const userRoles = store.state.roles || [];
      console.log(userRoles)
      const accessibleRoutes = filterRoutesByRole(dynamicRoutes, userRoles);
    
      // 先移除可能已存在的动态路由
      router.getRoutes().forEach((r) => {
        if (dynamicRoutes.some((dr) => dr.name === r.name)) {
          router.removeRoute(r.name!);
        }
      });
    
      // 添加新路由
      accessibleRoutes.forEach((route) => {
        router.addRoute(route);
      });
    }
    // 完结...
    
    // 登录按钮
    const submitForm = async () => {
      try {
        // 尝试对表单进行验证,如果验证不通过,则不会执行后续代码
        await formRef.value?.validate();
    
        // 使用 axios 发送 POST 请求到服务器的登录接口
        // 将用户名和密码作为请求体发送
        const response = await axios.post("/api/users/login", {
          username: ruleForm.value.usermobile, // 用户名字段在请求体中
          password: ruleForm.value.userpwd, // 密码字段在请求体中
        });
    
        // 打印响应对象到控制台
        console.log(response);
    
        // 弹出响应消息提示用户
        message.info(response.data.msg);
        // alert(response.data.msg);
    
        // 从响应数据中提取 token、用户 ID 和用户名
        const role_code: string = response.data.data.userInfo.role_code; // 角色的唯一标识
    
        // 注意:这里存在vuex中的数据应该是一个数组,方便后续处理   
        let role_code_arr = ref<string[]>([]);
        role_code_arr.value.push(role_code);
        // 将角色的编码存到vuex中
        store.commit("SET_ROLES", role_code_arr);
    
        // 生成动态路由
        generateDynamicRoutes();
          
      } catch (error: any) {
        // 如果请求失败或验证失败,则捕获错误并打印到控制台
        console.error("请求失败:", error);
        message.error(error.response.data.msg);
      }
    };
    

    导航守卫:router/index.ts :

    import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
    // import { useUserStore } from '@/store/user'
    import { useStore } from "vuex";
    // 路由组件导入
    const HomeView = () => import('../views/HomeView.vue')
    const UserView = () => import('../views/UserView.vue')
    const RoleView = () => import('@/views/RoleView.vue')
    const PermissView = () => import('@/views/PermissView.vue')
    const LoginView = () => import('../views/LoginView.vue')
    const NotFoundView = () => import('../views/NotFound.vue')
    
    
    // 静态路由
    const staticRoutes = [
      {
        path: '/login',
        name: 'Login',
        component: LoginView
      },
      {
        path: '/404',
        name: 'NotFound',
        component: NotFoundView
      }
    ];
    
    // 动态路由
    export const dynamicRoutes = [
      {
        path: '/admin',
        name: 'admin',
        component: HomeView,
        meta: {
          title: "首页",
          title_path: '/admin',
          sub_title: "后台管理",
          roles: ['admin', 'accountA', 'accountB'] // 修正为数组格式
        },
        children: [
          {
            path: 'user',
            name: 'user',
            component: UserView,
            meta: {
              title: "用户管理",
              title_path: '/admin/user',
              sub_title: "用户信息编辑",
              roles: ['admin', 'accountA', 'accountB'] // 修正为数组格式
            }
          },
          {
            path: 'role',
            name: 'role',
            component: RoleView,
            meta: {
              title: "角色管理",
              title_path: '/admin/role',
              sub_title: "角色信息编辑",
              roles: ['admin', 'accountA'] // 修正为数组格式
            }
          },
          {
            path: 'permis',
            name: 'permis',
            component: PermissView,
            meta: {
              title: "权限管理",
              title_path: '/admin/permis',
              sub_title: "权限信息编辑",
              roles: ['admin'] // 修正为数组格式
            }
          }
        ]
      }
    ]
    
    const router = createRouter({
      // history: createWebHistory(import.meta.env.BASE_URL),
      history: createWebHistory(process.env.BASE_URL),
      routes:staticRoutes
    })
    
    // 导航守卫
    router.beforeEach((to, from, next) => {
      const store = useStore();
      const userRoles = to.meta.roles || [];
      console.log(store.state.roles)
      // 如果路由需要权限验证
      if (to.meta.roles) {
        // const hasPermission = to.meta.roles.some(role => userStore.roles.includes(role));
        const hasPermission = userRoles.some((role:any) => store.state.roles.includes(role));
    
        // const hasPermission = to.meta.roles.includes(store.roles);
        if (!hasPermission) {
          return next({ name: 'NotFound' }); // 无权限时跳转到 404 页面
        }
      }
    
      next(); // 允许访问
    });
    
    export default router
    

    生成动态菜单:HomeView.vue:

import { useStore } from "vuex";
const store = useStore();

import { useRouter, useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();

// 现生成一个动态菜单--需要从meta中拿到
const all_router = router.getRoutes();
// 把全部的路由meta拿到
const all_meta_data = all_router.map((item) => {
  return item.meta;
});
// 过滤出isMenu === true的meta
const meta_data = all_meta_data.filter((item) => {
  return item.isMenu === true;
});
// 从vuex中拿到此用户的角色组
const userRoles = store.state.roles || [];
// 过滤出此角色可以访问的路由meta
const finish_meta = meta_data.filter((item) => {
  return item.roles.some((role: string) => userRoles.includes(role));
  // return item.roles.includes(store.state.st)
});
// 最后拿到可以给菜单使用的数组菜单
const iconComponents = {  // 图标的命名,由于meta中的icon是字符串,这里也是一种解决方法
  AppstoreOutlined: AppstoreOutlined,
  InboxOutlined: InboxOutlined,
  DesktopOutlined: DesktopOutlined
};
const use_meta = finish_meta.map((item) => {
  return {
    key:item.title_path,
    // icon:item.icon.replace(/^["']|["']$/g, ''),
    // icon: iconMap[item.icon] || null,
    icon: iconComponents[item.icon],
    label:item.title
  }
});
  1. 路由导航
    • 每次路由跳转时,路由守卫会检查:
    ◦ 目标路由是否需要特定权限
    ◦ 当前用户是否拥有所需权限
    • 根据检查结果允许或拒绝访问

  2. 用户注销

    function logout() {
      // 清除用户信息
      store.commit('CLEAR_USER')
      
      // 重置路由
      router.getRoutes().forEach(route => {
        if (dynamicRoutes.some(dr => dr.name === route.name)) {
          router.removeRoute(route.name!)
        }
      })
      
      // 跳转到登录页
      router.push('/login')
    }
    

检查用户角色操作的作用分析

您提供的代码中关于用户角色检查的部分实际上是非常必要的,它在整个权限控制流程中扮演着关键角色。让我详细解释其作用和必要性:

一、角色检查的核心作用

1. 权限过滤的核心机制
function filterRoutesByRole(routes: any[], userRoles: string[]) {
  return routes.filter((route) => {
    return (
      !route.meta?.roles || // 无权限限制的路由直接放行
      route.meta.roles.some((role: string) => userRoles.includes(role)) // 检查角色匹配
    );
  });
}

这段代码实现了:
路由筛选:根据用户角色过滤出可访问的路由
权限验证:确保用户只能看到自己有权限访问的路由
安全控制:防止越权访问敏感路由

2. 动态路由生成流程
登录模块 路由系统 状态管理 存储用户角色(如['admin']) 触发generateDynamicRoutes 清除旧路由 过滤出可访问路由 添加新路由 登录模块 路由系统 状态管理

二、为什么不能省略?

1. 必要性分析
检查环节作用省略后果
角色存储保留用户权限标识无法识别用户权限级别
路由过滤生成个性化路由表所有用户看到相同菜单
权限验证防止越权访问安全漏洞风险
2. 实际应用场景

假设:
• 用户角色:['editor']
• 路由配置:

[
  { path: '/admin', meta: { roles: ['admin'] }},
  { path: '/editor', meta: { roles: ['editor'] }}
]

无过滤时:用户可以看到/admin路由但无法正常使用,导致错误
有过滤时:用户只能看到/editor路由,体验更合理

三、代码优化建议

1. 类型安全改进
// 在类型声明文件中
declare module 'vue-router' {
  interface RouteMeta {
    roles?: string[];
    // 其他元字段...
  }
}

// 过滤函数改进
function filterAccessibleRoutes(routes: RouteRecordRaw[], userRoles: string[]): RouteRecordRaw[] {
  return routes.filter(route => {
    const requiredRoles = route.meta?.roles || []
    return requiredRoles.length === 0 || 
           requiredRoles.some(role => userRoles.includes(role))
  })
}
2. 性能优化
// 避免重复计算
const userRoles = computed(() => store.state.roles)

// 路由添加前检查
function needsRefresh(newRoutes: RouteRecordRaw[]) {
  const currentRoutes = router.getRoutes()
  return (
    newRoutes.length !== currentRoutes.length ||
    newRoutes.some(route => !currentRoutes.some(r => r.path === route.path))
  )
}
3. 错误处理增强
function generateDynamicRoutes() {
  try {
    const userRoles = store.state.roles || []
    if (!Array.isArray(userRoles)) {
      throw new Error('角色数据格式错误')
    }
    
    const accessibleRoutes = filterRoutesByRole(dynamicRoutes, userRoles)
    
    // 清除旧路由逻辑...
    // 添加新路由逻辑...
    
  } catch (err) {
    console.error('路由生成失败:', err)
    router.push('/error?code=route_init_failed')
  }
}

四、完整工作流程

  1. 用户登录
    • 获取角色信息 → 存储到Vuex

  2. 路由生成

    用户角色
    路由过滤
    清除旧路由
    添加新路由
    菜单渲染
  3. 访问控制
    • 路由守卫二次验证
    • 菜单动态生成

五、总结

您代码中的角色检查操作:
• ✅ 不是多余的:是权限系统的核心逻辑
• ✅ 必不可少:确保路由与权限的精确匹配
• ✅ 可以优化:类型、性能、错误处理等方面

建议保留这部分逻辑,同时参考上述优化建议进行改进,可以使您的权限控制系统更加健壮和安全。

四、最佳实践方案

4.1 路由配置规范

字段类型必填说明
pathstring路由路径
componentComponent组件引用
meta.rolesstring[]允许的角色
meta.titlestring推荐页面标题
meta.iconstring可选菜单图标
meta.cacheboolean是否缓存

4.2 权限检查方案对比

方案优点缺点适用场景
前端控制响应快,体验好安全性较低内部管理系统
前后端结合安全性高实现复杂高安全要求系统
动态接口灵活度高性能开销大权限频繁变更系统

4.3 性能优化建议

  1. 路由懒加载

    component: () => import('@/views/HeavyPage.vue')
    
  2. 路由分组打包

    // vite.config.js
    rollupOptions: {
      output: {
        manualChunks: {
          admin: ['@/views/Admin*.vue']
        }
      }
    }
    
  3. 持久化缓存

    // 使用pinia-plugin-persistedstate
    persist: {
      paths: ['user.roles']
    }
    

五、常见问题解决方案

5.1 问题排查表

现象可能原因解决方案
路由跳转循环守卫逻辑错误检查重定向条件
菜单不更新路由未正确重置确保先remove后add
404错误路由未加载检查addRoute调用
权限失效角色信息丢失检查状态持久化

5.2 典型错误处理

// 安全的路由添加方式
function safeAddRoute(route) {
  try {
    if (router.hasRoute(route.name)) {
      router.removeRoute(route.name)
    }
    router.addRoute(route)
    return true
  } catch (err) {
    console.error('路由添加失败:', err)
    return false
  }
}

六、完整示例项目结构

/src
├── router
│   ├── index.ts        # 路由入口
│   ├── static.ts       # 静态路由
│   └── dynamic.ts      # 动态路由配置
├── stores
│   └── auth.ts         # 权限状态管理
├── utils
│   └── permission.ts   # 权限验证工具
└── views
    ├── public          # 公共页面
    └── admin           # 权限页面

通过这套系统化方案,开发者可以快速实现:

  1. 基于角色的精细化权限控制
  2. 动态菜单的自动生成
  3. 安全的访问验证机制
  4. 良好的用户体验和性能表现

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

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

相关文章

忘记mysql的root用户密码(已解决)

1、打开数据库可视化界面&#xff08;比如MySQL workbench&#xff09; 2、执行select host,user,authentication_string from mysql.user; 3、把‘authentication_string’下面的字段 复制到MD5在线解密网页中&#xff08;比如md5在线解密&#xff09;

ubuntu 20.04 编译和运行SC-LeGo-LOAM

1.搭建文件目录和clone代码 mkdir -p SC-LeGo-LOAM/src cd SC-LeGo-LOAM/src git clone https://github.com/AbangLZU/SC-LeGO-LOAM.git cd .. 2.修改代码 需要注意的是原作者使用的是Ouster OS-64雷达&#xff0c;需要更改utility.h文件中适配自己的雷达类型&#xff0c;而…

CentOS 7安装hyperscan

0x00 前言 HyperScan是一款由Intel开发的高性能正则表达式匹配库&#xff0c;专为需要快速处理大量数据流的应用场景而设计。它支持多平台运行&#xff0c;包括Linux、Windows和macOS等操作系统&#xff0c;并针对x86架构进行了优化&#xff0c;以提供卓越的性能表现。HyperSc…

UE5 Simulation Stage

首先将Grid2D创建出来&#xff0c;然后设置值&#xff0c;Grid2D类似于在Niagara系统中的RenderTarget2D&#xff0c;可以进行绘制&#xff0c;那么设置大小为512 * 512 开启Niagara粒子中的Simulation Stage 然后开始编写我们的自定义模块 模块很简单&#xff0c;TS就是Textur…

Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器

文章目录 前言问题描述简单说&#xff1a;痛点分析&#xff1a;到底难在哪&#xff1f;1. 子树的概念搞不清楚2. 要不要“递归”&#xff1f;递归从哪开始&#xff1f;3. 怎么“边遍历边判断”&#xff1f;这套路不熟 后序遍历 全局计数器遍历过程解释一下&#xff1a;和实际场…

增益调度控制 —— 理论、案例与交互式 GUI 实现

目录 增益调度控制 —— 理论、案例与交互式 GUI 实现一、引言二、增益调度控制的基本原理三、数学模型与公式推导四、增益调度控制的优势与局限4.1 优势4.2 局限五、典型案例分析5.1 案例一:航空飞行控制中的增益调度5.2 案例二:发动机推力控制中的增益调度5.3 案例三:化工…

关于OEC/OEC-turbo刷机问题的一些解决方法(2)——可能是终极解决方法了

前面写了两篇关于OEC/OEC-turbo刷机问题的文章了&#xff0c;从刷机过程、刷机中遇到的问题&#xff0c;以及遇到最多但始终无法有效解决的下载boot失败的问题的剖析&#xff0c;最近确实也做了一些工作&#xff0c;虽然没有最终解决&#xff0c;但也算是这系列文章里面阶段性的…

瓦片数据合并方法

影像数据 假如有两份影像数据 1.全球底层影像0-5级别如下&#xff1a; 2.局部高清影像数据级别9-14如下&#xff1a; 合并方法 将9-14文件夹复制到全球底层0-5的目录下 如下&#xff1a; 然后合并xml文件 使得Tileset设置到最高级&#xff08;包含所有级别&#xff09;&…

第16届蓝桥杯单片机模拟试题Ⅰ

试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //onewire.c float getT(); //sys.c extern unsigned char UI; extern bit touch_mode; extern float jiaozhun; extern float canshu; extern float temper; void init74hc138(unsigned…

mac 卸载流氓软件安全助手

之前个人电脑在公司使用过一段时间&#xff0c;为了使用网线联网安装了公司指定的 联软上网助手&#xff0c;谁知安装容易卸载难&#xff0c;后来找运维来卸载&#xff0c;输入管理员密码后&#xff0c;也无反应&#xff0c;最后不了了之了&#xff0c;这个毒瘤软件长期在后台驻…

⭐算法OJ⭐滑动窗口最大值【双端队列(deque)】Sliding Window Maximum

文章目录 双端队列(deque)详解基本特性常用操作1. 构造和初始化2. 元素访问3. 修改操作4. 容量操作 性能特点时间复杂度&#xff1a;空间复杂度&#xff1a; 滑动窗口最大值题目描述方法思路解决代码 双端队列(deque)详解 双端队列(deque&#xff0c;全称double-ended queue)是…

沧州铁狮子

又名“镇海吼”&#xff0c;是中国现存年代最久、形体最大的铸铁狮子&#xff0c;具有深厚的历史文化底蕴和独特的艺术价值。以下是关于沧州铁狮子的详细介绍&#xff1a; 历史背景 • 铸造年代&#xff1a;沧州铁狮子铸造于后周广顺三年&#xff08;953年&#xff09;&#…

Python•判断循环

ʕ⸝⸝⸝˙Ⱉ˙ʔ ♡ 判断🍰常用的判断符号(比较运算符)andor括号notin 和 not inif-elif-else循环🍭计数循环 forrange()函数简易倒计时enumerate()函数zip()函数遍历列表遍历元组遍历字符串遍历字典条件循环 while提前跳转 continue跳出循环 break能量站😚判断🍰 …

【力扣hot100题】(060)分割回文串

每次需要判断回文串&#xff0c;这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …

C++---day7

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std;class Stu { private:public:};// 自定义 vector 类&#xff0c;重…

SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

flink 增量快照同步文件引用关系和恢复分析

文章目录 文件引用分析相关代码分析从state 恢复&#xff0c;以rocksdb为例不修改并行度修改并行度keyGroupRange过程问题 文件引用分析 每次生成的checkpoint 里都会有所有文件的引用信息 问题&#xff0c;引用分析里如何把f1,f2去掉了&#xff0c;可以参考下面的代码&#…

c++概念—内存管理

文章目录 c内存管理c/c的内存区域划分回顾c语言动态内存管理c动态内存管理new和delete的使用new和delete的底层逻辑operator new函数和operator delete函数new和delete的实现操作方式不匹配的情况定位new new/delete和malloc/free的区别 c内存管理 在以往学习c语言的过程中&…

无人机双频技术及底层应用分析!

一、双频技术的核心要点 1. 频段特性互补 2.4GHz&#xff1a;穿透力强、传输距离远&#xff08;可达5公里以上&#xff09;&#xff0c;适合复杂环境&#xff08;如城市、建筑物密集区&#xff09;&#xff0c;但易受Wi-Fi、蓝牙等设备的干扰。 5.8GHz&#xff1a;带宽更…

【电视软件】小飞电视v2.7.0 TV版-清爽无广告秒换台【永久更新】

软件介绍 小飞电视是一款电视端的直播软件&#xff0c;无需二次付费和登录&#xff0c;资源丰富&#xff0c;高清流畅。具备开机自启、推送功能、自定义直播源、个性化设置及节目预告等实用功能&#xff0c;为用户带来良好的观看体验。基于mytv开源项目二改&#xff0c;涵盖央…