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 按钮组合,可自由控制显示与模块前缀
相关推荐
华玥作者14 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_14 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠14 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang2015092815 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC15 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务16 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整16 小时前
面试点(网络层面)
前端·网络
VT.馒头16 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy17 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron070718 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js