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 按钮组合,可自由控制显示与模块前缀
相关推荐
子兮曰15 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰15 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万16 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝16 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋16 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁17 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王952718 小时前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大19 小时前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师19 小时前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学19 小时前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端