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中没有 → 按钮被移除
相关推荐
J总裁的小芒果3 小时前
vue3 全局定义动态样式
前端·javascript·vue.js
whalekv3 小时前
10月25日
前端·javascript·vue.js
xuelong-ming3 小时前
uniapp vue3 点击跳转外部网页
vue.js·uni-app
万邦科技Lafite5 小时前
京东按图搜索京东商品(拍立淘) API (.jd.item_search_img)快速抓取数据
开发语言·前端·数据库·python·电商开放平台·京东开放平台
Never_Satisfied7 小时前
在JavaScript / Node.js / 抖音小游戏中,使用tt.request通信
开发语言·javascript·node.js
一只小透明啊啊啊啊7 小时前
Java Web 开发的核心组件:Servlet, JSP,Filter,Listener
java·前端·servlet
你的人类朋友8 小时前
设计模式有哪几类?
前端·后端·设计模式
Yeats_Liao8 小时前
Go Web 编程快速入门 10 - 数据库集成与ORM:连接池、查询优化与事务管理
前端·数据库·后端·golang
啃火龙果的兔子8 小时前
前端八股文react篇
前端·react.js·前端框架