Vue自定义指令实现点击事件权限拦截控制的npm插件

🎸 把一篇老文章内容 vibecoding 成了 npm 包

以前写过一篇关于「Vue 自定义指令实现按钮权限拦截」的文章。想法挺好,但每次新项目都要从文章里复制代码到 main.ts,总感觉差点意思。

于是最近干脆把它 vibecoding 成了一个正经的 Vue 插件,发到 npm 上了。

原文:基于 Vue 自定义指令实现点击事件权限拦截控制


🤔 为什么需要这个?

大多数项目做到路由权限、接口权限就差不多了,很少有人会细化到按钮点击这个粒度。

但真遇到了就发现有几个痛点:

  • 封装组件不现实 ------ 给每个 el-button 包一层 PermissionButton,Props 透传写到手软
  • UI 库不统一 ------ Element Plus、Ant Design Vue、Naive UI......换一个就要重新封一套
  • 原生元素也逃不掉 ------ <button><div><a>,封起来没完没了

Vue 自定义指令的方案刚好打在痛点上------直接操作原生 DOM 事件,跟 UI 库无关。


🧠 设计思路

插件只做一件事:拦截 click,传给 check,通过就放行,不通过就调 onDeny。

安装时注册 check 函数

ts 复制代码
app.use(VueInterceptPlugin, {
  check: (ctx) => userStore.hasPermission(ctx.id),
  onDeny: (ctx) => {
    ElMessage.warning(ctx.name,'无权操作')
  },
})

check 返回 true 放行、false 拦截,判断逻辑完全由你决定------可以从 ctx.el.dataset 读属性,可以从 ctx.value 读原始值,怎么方便怎么来。

两种写法

html 复制代码
<!-- 无参数:直接传函数 -->
<el-button v-intercept="handleDelete">删除</el-button>

<!-- 带参数:数组第一个是函数,后面随便传 -->
<el-button v-intercept="[handleDeleteById, 1001]">删除订单 #1001</el-button>
<el-button v-intercept="[handleDeleteById, 1002, '加急']">删除订单 #1002</el-button>

handler 里只需要写业务逻辑:

ts 复制代码
const handleDelete = () => { deleteApi() }
const handleDeleteById = (id: number) => { deleteApi(id) }

不传事件对象,参数就是你给的值,不搞隐式追加。

check 可以怎么判断?

check 收到的 ctx 包含 elhandlervalue,想怎么判断都行:

ts 复制代码
check: (ctx) => {
  // 从元素属性判断
  return ctx.el.dataset.role === 'admin'

  // 从原始值判断(数组传参场景)
  // const [fn, id, type] = ctx.value
  // return id !== 1001
}

🔄 Vue 2 / Vue 3 兼容

内部检测 app.version,自动切换指令钩子:

Vue 版本 绑定 更新 卸载
Vue 3 mounted updated unmounted
Vue 2 bind update unbind

一套代码,双平台通用。


🎯 用起来

bash 复制代码
npm install vue-intercept-plugin
ts 复制代码
// Vue 3 --- main.ts
import { createApp } from 'vue'
import VueInterceptPlugin from 'vue-intercept-plugin'

const app = createApp(App)
app.use(VueInterceptPlugin, {
  check: (ctx) => checkPermission(ctx.el.dataset.perm),
  onDeny: () => ElMessage.warning('无权操作'),
})
html 复制代码
<template>
  <el-button
    v-intercept="handleDelete"
    data-perm="delete"
    type="danger"
  >
    删除
  </el-button>
</template>

🔧 实现细节

  • WeakMap 存储 ------ 元素和事件监听函数的映射存在 WeakMap 里,不污染 DOM,元素销毁后自动回收
  • SSR 安全 ------ 检测到 window 不存在时直接跳过,Nuxt 等环境不报错
  • 单元测试覆盖 ------ Vitest + jsdom,覆盖权限放行/拦截、数组传参、边界情况等
  • 零依赖 ------ 只有 3KB,无外部依赖

💬 最后


相关推荐
竹林81823 分钟前
Solana前端开发:我在一个NFT铸造页面上被@solana/web3.js的Connection和Transaction签名坑了两天
前端
冬奇Lab41 分钟前
每日一个开源项目(第144篇):ai-website-cloner-template - 一条命令、多 Agent 并行,把任意网站逆向成 Next.js 代码
前端·人工智能·开源
玄玄子1 小时前
webpack publicPath作用原理
前端·webpack·程序员
HduSy1 小时前
帮 Claude Code 做了个菜单栏 Token 看板,聊聊里面的一些实现逻辑
前端
用户059540174461 小时前
用了6个月LangChain,才发现AI Agent的记忆存储一直有坑——写了23个Pytest用例才彻底修好
前端·css
奶油mm1 小时前
我偷偷把公司的祖传 jQuery 项目改成了 Vue3,CTO 没发现,但全组都来抄我的代码了
前端
用户2136610035721 小时前
Vue2非父子通信与动态组件
前端·vue.js
PedroQue991 小时前
Vite插件体系1.0.0:API稳定,生产就绪
前端·vite
用户059540174461 小时前
把LLM记忆测试从手工脚本换成Pytest参数化,回归时间从2小时降到10分钟
前端·css
donecoding1 小时前
3 条命令搞定闭环 Monorepo:Lerna 版本管理 + 拓扑构建 + 自定义分发
前端·前端框架·node.js