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 按钮组合,可自由控制显示与模块前缀
相关推荐
hpoenixf5 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特5 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷5 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian6 小时前
前端node常用配置
前端
华洛6 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq6 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A7 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常7 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端
小码哥_常8 小时前
从Groovy到KTS:Android Gradle脚本的华丽转身
前端
灵感__idea8 小时前
Hello 算法:复杂问题的应对策略
前端·javascript·算法