最近公司的老项目进行重构,前端技术栈也从原来的 AngularJS 转到 Vue,在架构到页面按钮级别的权限这一块时,我打算利用 vue 的自定义指令来实现。今天就来记录一下实现方式,话不多说,直接上代码。
v-permission 自定义指令
Vue 自定义指令有全局注册和局部注册两种方式,考虑到项目中全局都要用到,所以我们这里采用的是全局注册的方式。
-
在
src
目录下新建directives
文件夹,并创建permission.js
以及index.js
。// permission.js import Store from '../store/index.js' const checkPermission = (productProviderName, productName, action) => { const permissionObj = Store.getters.permissions if (!permissionObj[productProviderName]) return false const permissions = permissionObj[productProviderName][productName] if (!permissions) return false return permissions.indexOf(action) > -1 } function fn (el, binding) { let permission = binding.value // 获取到 v-permission 所绑定的值 if (typeof permission === 'string') { if (permission) { const arr = permission.split('.') if (arr.length === 3) { let hasPermission = checkPermission(arr[0], arr[1], arr[2]) if (!hasPermission) { // 没有权限则移除 dom 元素 el.parentNode && el.parentNode.removeChild(el) } else { // 有权限则追加之前缓存的 dom 元素 el.cacheParentElement && el.cacheParentElement.appendChild(el.cacheElement) } } else { console.error(`The value bound to v-permission should be like v-permission="'aliyun.ecs.PURCHASE'".`) } } else { console.error('The value bound to v-permission cannot be empty.') } } else { console.error('The value type bound to v-permission should be String.') } } const permission = { inserted: function (el, binding) { // !!!敲重点 el.cacheElement = el // 缓存本节点 el.cacheParentElement = el.parentNode // 缓存父节点 fn(el, binding) }, update: function (el, binding) { fn(el, binding) } } export default permission
// index.js import permission from './permission' const directives = { permission } export default { install(Vue) { // 批量注册自定义指令 Object.keys(directives).forEach((key) => { Vue.directive(key, directives[key]) }) } }
-
在
main.js
中引入并调用import Vue from 'vue' import directives from './directives/index.js' Vue.use(directives) // 以插件的方式引入
-
在组件中的使用方式
<template> <button v-permission="'aliyun.ecs.PURCHASE'">Create Instance</el-button> </template>
Vue 自定义指令相关拓展
钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
-
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 -
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 -
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 -
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。 -
unbind
:只调用一次,指令与元素解绑时调用。
钩子函数参数
指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为 2。oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。
vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。
想要了解更多,请移步官方文档。
Vue 插件相关拓展
使用插件
通过全局方法 Vue.use()
使用插件。它需要在你调用 new Vue()
启动应用之前完成。
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin, options)
new Vue({
// ...组件选项
})
开发插件
Vue.js
的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。
const MyPlugin = {
install(Vue, options) {
// do something
}
}
export default MyPlugin
想要了解更多,请移步官方文档。