Vue3路由

静态路由:

公共路由(没有permissions)

动态路由:

后端新增菜单表,前端自动生成

┌─────────────────────────────────────────────────────────────────┐

│ 第一步:用户登录 │

└─────────────────────────────────────────────────────────────────┘

POST /login { username: 'ry', password: 'xxx' }

返回: { token: 'eyJhbGc...' }

localStorage.setItem('Admin-Token', token)

┌─────────────────────────────────────────────────────────────────┐

│ 第二步:路由守卫拦截 (permission.js) │

└─────────────────────────────────────────────────────────────────┘

检查 useUserStore().roles.length === 0

是 → 执行第三步

┌─────────────────────────────────────────────────────────────────┐

│ 第三步:获取用户信息和权限 │

└─────────────────────────────────────────────────────────────────┘

useUserStore().getInfo() → GET /getInfo

返回数据:

{

user: { userId: 2, userName: 'ry', ... },

roles: ['common'], ← 角色列表

permissions: [ ← 权限标识列表

'pm:project:query', ✅ 项目列表权限

'pm:project:edit',

// 注意:没有 'pm:project:add' ❌ 没有新增权限

]

}

存储到 Store:

  • userStore.roles = ['common']

  • userStore.permissions = ['pm:project:query', ...]

┌─────────────────────────────────────────────────────────────────┐

│ 第四步:生成动态路由 │

└─────────────────────────────────────────────────────────────────┘

usePermissionStore().generateRoutes()

GET /getRouters → 返回该用户可访问的菜单/路由

后端返回 JSON (根据角色权限过滤后):

{

"data": [

{

"name": "ProjectManagement",

"path": "/projectManagement",

"component": "Layout",

"meta": { "title": "项目管理", "icon": "project" },

"children": [

{

"name": "Project",

"path": "project",

"component": "projectManagement/project/index",

"meta": {

"title": "项目列表",

"icon": "list"

}

}

]

}

]

}

filterAsyncRouter() 转换组件:

'Layout' → Layout组件

'projectManagement/project/index' →

() => import('@/views/projectManagement/project/index.vue')

router.addRoute(route) 动态注册到路由表

渲染侧边栏菜单(显示"项目管理" → "项目列表")

┌─────────────────────────────────────────────────────────────────┐

│ 第五步:用户访问项目列表页面 │

└─────────────────────────────────────────────────────────────────┘

访问: /projectManagement/project

加载页面组件: projectManagement/project/index.vue

页面级权限控制

javascript 复制代码
<template>
  <div>
    <!-- 查询表单 -->
    <el-form>...</el-form>
    
    <!-- 操作按钮区 -->
    <el-row>
      <!-- ✅ 新增按钮 - 需要 pm:project:add 权限 -->
      <el-button
        type="primary"
        icon="Plus"
        @click="handleAdd"
        v-hasPermi="['pm:project:add']"
      >新增项目</el-button>
      
      <!-- ✅ 导出按钮 - 需要 pm:project:export 权限 -->
      <el-button
        type="warning"
        icon="Download"
        @click="handleExport"
        v-hasPermi="['pm:project:export']"
      >导出</el-button>
    </el-row>
    
    <!-- 数据表格 -->
    <el-table :data="projectList">
      <el-table-column label="项目名称" prop="projectName" />
      <el-table-column label="操作">
        <template #default="scope">
          <!-- ✅ 编辑按钮 - 需要 pm:project:edit 权限 -->
          <el-button
            link
            type="primary"
            icon="Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['pm:project:edit']"
          >修改</el-button>
          
          <!-- ✅ 删除按钮 - 需要 pm:project:remove 权限 -->
          <el-button
            link
            type="danger"
            icon="Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['pm:project:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

按钮级-v-hasPermi 指令工作原理

根据已读取的代码,v-hasPermi 指令的实现逻辑:

javascript 复制代码
// src/directive/permission/hasPermi.js
export default {
  mounted(el, binding) {
    const { value } = binding
    const all_permission = "*:*:*"
    const permissions = useUserStore().permissions  // 从store获取权限列表
    
    if (value && value instanceof Array && value.length > 0) {
      const permissionFlag = value
      
      // 检查是否有对应的权限
      const hasPermissions = permissions.some(permission => {
        return all_permission === permission || permissionFlag.includes(permission)
      })
      
      // 如果没有权限,移除DOM元素
      if (!hasPermissions) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    }
  }
}

两级权限控制

第一级:路由级(菜单显示)

// 后端 /getRouters 接口会检查:

// 用户是否有 'pm:project:list' 权限

if (hasPermission('pm:project:list')) {

// ✅ 返回"项目列表"菜单

return { path: 'project', component: '...' }

} else {

// ❌ 不返回该菜单,侧边栏不显示

}

第二级:按钮级(功能控制)

<!-- 前端 v-hasPermi 指令检查 -->

<el-button v-hasPermi="['pm:project:add']">新增</el-button>

<!-- 如果 permissions 中没有 'pm:project:add',按钮DOM被移除 -->

总结

javascript 复制代码
// 1. 登录成功,存储token
localStorage.setItem('Admin-Token', 'xxx')

// 2. 路由守卫触发
router.beforeEach((to, from, next) => {
  if (useUserStore().roles.length === 0) {
    
    // 3. 获取用户信息
    useUserStore().getInfo().then(() => {
      // → roles: ['common']
      // → permissions: ['pm:project:query', 'pm:project:edit']
      
      // 4. 生成动态路由
      usePermissionStore().generateRoutes().then(routes => {
        // 5. 注册路由
        routes.forEach(route => router.addRoute(route))
        next({ ...to, replace: true })
      })
    })
  }
})

// 6. 进入页面,按钮权限控制
// v-hasPermi="['pm:project:add']"
// → permissions中没有 → 按钮被移除
相关推荐
天意pt1 天前
Blog-SSR 系统操作手册(v1.0.0)
前端·vue.js·redis·mysql·docker·node.js·express
遗憾随她而去.1 天前
Webpack5 高级篇(一)
前端
遇见~未来1 天前
JavaScript构造函数与Class终极指南
开发语言·javascript·原型模式
清风ai明月1 天前
在vue3中Promise是什么
vue.js
疯狂踩坑人1 天前
【React 19 尝鲜】第一篇:use和useActionState
前端·react.js
毕设源码-邱学长1 天前
【开题答辩全过程】以 基于VUE的打车系统的设计与实现为例,包含答辩的问题和答案
前端·javascript·vue.js
用户39051332192881 天前
JS判断空值只知道“||”?不如来试试这个操作符
前端·javascript
海云前端11 天前
前端面试必问 asyncawait 到底要不要加 trycatch 90% 人踩坑 求职加分技巧揭秘
前端
麦麦大数据1 天前
J009 美食推荐可视化大数据系统vue+springboot
vue.js·spring boot·mysql·推荐算法·美食·可视化分析·沙箱支付
rfidunion1 天前
springboot+VUE+部署(1。新建项目)
java·vue.js·spring boot