vue3-封装权限按钮组件和自定义指令

"权限按钮组件"在中大型前端项目中是非常通用的一类功能组件,通常用于根据用户权限动态显示 CRUD 按钮(增删改查)。

下面设计一套:

  • ✅ Vue 3 + TypeScript 写法
  • ✅ 支持 v-permission 或权限数组控制
  • ✅ 封装单个 CRUD 按钮
  • ✅ 提供组合按钮容器(任意组合增删改查)
  • ✅ 支持统一样式、禁用态与事件透传

🧩 一、权限控制思路

假设你有一个权限系统,每个按钮对应一个权限码,例如:

ts 复制代码
"sys:user:add"      // 新增
"sys:user:edit"     // 修改
"sys:user:delete"   // 删除
"sys:user:view"     // 查询

用户登录后,存储在 userStore 中:

ts 复制代码
userStore.permissions = ['sys:user:view', 'sys:user:edit']

✅ 二、权限按钮指令(v-permission)

创建一个通用权限指令:

ts 复制代码
// directives/permission.ts
import { Directive } from "vue";
import { useUserStore } from "@/store/modules/user";

export const permission: Directive = {
  mounted(el, binding) {
    const userStore = useUserStore();
    const requiredPerm = binding.value as string;

    if (!userStore.permissions.includes(requiredPerm)) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  },
};

注册全局指令:

ts 复制代码
// main.ts
import { permission } from "@/directives/permission";
app.directive("permission", permission);

✅ 三、单个权限按钮组件

vue 复制代码
<!-- components/AuthButton.vue -->
<template>
  <el-button
    v-if="hasPermission"
    :type="type"
    :icon="icon"
    :disabled="disabled"
    @click="onClick"
  >
    <slot>{{ label }}</slot>
  </el-button>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { useUserStore } from "@/store/modules/user";

interface Props {
  /** 权限码,例如 sys:user:add */
  perm: string;
  /** 按钮文字 */
  label?: string;
  /** Element Plus 按钮类型 */
  type?: string;
  /** 图标 */
  icon?: string;
  /** 是否禁用 */
  disabled?: boolean;
}

const props = defineProps<Props>();
const emit = defineEmits(["click"]);

const userStore = useUserStore();

// 权限校验
const hasPermission = computed(() =>
  userStore.permissions.includes(props.perm)
);

const onClick = () => {
  emit("click");
};
</script>

✅ 四、CRUD 组合按钮组件

该组件可以自由组合 "增删改查" 四种按钮。

vue 复制代码
<!-- components/AuthCrudButtons.vue -->
<template>
  <div class="auth-crud-buttons">
    <AuthButton
      v-if="showAdd"
      perm="sys:user:add"
      type="primary"
      icon="Plus"
      label="新增"
      @click="$emit('add')"
    />
    <AuthButton
      v-if="showEdit"
      perm="sys:user:edit"
      type="warning"
      icon="Edit"
      label="编辑"
      @click="$emit('edit')"
    />
    <AuthButton
      v-if="showDelete"
      perm="sys:user:delete"
      type="danger"
      icon="Delete"
      label="删除"
      @click="$emit('delete')"
    />
    <AuthButton
      v-if="showView"
      perm="sys:user:view"
      type="info"
      icon="View"
      label="查看"
      @click="$emit('view')"
    />
  </div>
</template>

<script setup lang="ts">
import AuthButton from "./AuthButton.vue";

interface Props {
  /** 是否显示新增按钮 */
  showAdd?: boolean;
  /** 是否显示编辑按钮 */
  showEdit?: boolean;
  /** 是否显示删除按钮 */
  showDelete?: boolean;
  /** 是否显示查看按钮 */
  showView?: boolean;
}

defineProps<Props>();
defineEmits(["add", "edit", "delete", "view"]);
</script>

<style scoped>
.auth-crud-buttons {
  display: flex;
  gap: 8px;
}
</style>

✅ 五、使用示例

✅ 单个按钮

vue 复制代码
<AuthButton
  perm="sys:user:add"
  type="primary"
  label="新增"
  @click="handleAdd"
/>

若用户无 sys:user:add 权限,则按钮不会渲染。


✅ 组合 CRUD 按钮

vue 复制代码
<AuthCrudButtons
  :show-add="true"
  :show-edit="true"
  :show-delete="true"
  :show-view="false"
  @add="handleAdd"
  @edit="handleEdit"
  @delete="handleDelete"
/>

若用户只拥有 sys:user:viewsys:user:edit,则组件内部仅渲染"编辑"按钮。


✅ 六、进阶增强(推荐加上)

可以让 AuthCrudButtons 支持自定义权限码,让它在不同模块通用:

vue 复制代码
<script setup lang="ts">
import AuthButton from "./AuthButton.vue";

interface Props {
  prefix?: string; // 例如 'sys:user'
  showAdd?: boolean;
  showEdit?: boolean;
  showDelete?: boolean;
  showView?: boolean;
}

const props = defineProps<Props>();
defineEmits(["add", "edit", "delete", "view"]);

const getPerm = (suffix: string) => `${props.prefix}:${suffix}`;
</script>

<template>
  <div class="auth-crud-buttons">
    <AuthButton
      v-if="showAdd"
      :perm="getPerm('add')"
      type="primary"
      icon="Plus"
      label="新增"
      @click="$emit('add')"
    />
    <AuthButton
      v-if="showEdit"
      :perm="getPerm('edit')"
      type="warning"
      icon="Edit"
      label="编辑"
      @click="$emit('edit')"
    />
    <AuthButton
      v-if="showDelete"
      :perm="getPerm('delete')"
      type="danger"
      icon="Delete"
      label="删除"
      @click="$emit('delete')"
    />
    <AuthButton
      v-if="showView"
      :perm="getPerm('view')"
      type="info"
      icon="View"
      label="查看"
      @click="$emit('view')"
    />
  </div>
</template>

使用时:

vue 复制代码
<AuthCrudButtons prefix="sys:user" :show-add="true" :show-delete="true" />

✅ 七、总结

组件 作用
v-permission 指令级权限控制
AuthButton 单个按钮的权限封装
AuthCrudButtons CRUD 按钮组合,可自由控制显示与模块前缀
相关推荐
酒尘&3 小时前
JS数组不止Array!索引集合类全面解析
开发语言·前端·javascript·学习·js
学历真的很重要3 小时前
VsCode+Roo Code+Gemini 2.5 Pro+Gemini Balance AI辅助编程环境搭建(理论上通过多个Api Key负载均衡达到无限免费Gemini 2.5 Pro)
前端·人工智能·vscode·后端·语言模型·负载均衡·ai编程
用户47949283569154 小时前
"讲讲原型链" —— 面试官最爱问的 JavaScript 基础
前端·javascript·面试
用户47949283569154 小时前
2025 年 TC39 都在忙什么?Import Bytes、Iterator Chunking 来了
前端·javascript·面试
大怪v5 小时前
【Virtual World 04】我们的目标,无限宇宙!!
前端·javascript·代码规范
狂炫冰美式5 小时前
不谈技术,搞点文化 🧀 —— 从复活一句明代残诗破局产品迭代
前端·人工智能·后端
xw56 小时前
npm几个实用命令
前端·npm
!win !6 小时前
npm几个实用命令
前端·npm
代码狂想家6 小时前
使用openEuler从零构建用户管理系统Web应用平台
前端
dorisrv8 小时前
优雅的React表单状态管理
前端