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 按钮组合,可自由控制显示与模块前缀
相关推荐
漫游的渔夫8 分钟前
别再直接 `json.loads` 了!AI 返回的 JSON 坑位指南
前端·人工智能
软件工程师文艺19 分钟前
从0到1:Claude Code如何用React构建CLI应用
前端·react.js·前端框架
M ? A29 分钟前
Vue 迁移 React 实战:VuReact 一键自动化转换方案
前端·vue.js·经验分享·react.js·开源·自动化·vureact
yuki_uix30 分钟前
重排、重绘与合成——浏览器渲染性能的底层逻辑
前端·javascript·面试
沃尔威武1 小时前
调试黑科技:Chrome DevTools时间旅行调试实战
前端·科技·chrome devtools
yuki_uix1 小时前
虚拟 DOM 与 Diff 算法——React 性能优化的底层逻辑
前端·react.js·面试
yuki_uix1 小时前
从输入 URL 到页面显示——浏览器工作原理全解析
前端·面试
weixin_408099671 小时前
【完整教程】天诺脚本如何调用 OCR 文字识别 API?自动识别屏幕文字实战(附代码)
前端·人工智能·后端·ocr·api·天诺脚本·自动识别文字脚本
吴声子夜歌1 小时前
ES6——Generator函数详解
前端·javascript·es6
吴声子夜歌1 小时前
ES6——Set和Map详解
前端·javascript·es6