前端权限设计实现——按钮级

一直对权限设计很感兴趣,以前写后端代码时,搞过权限设计,挺有意思的,但是前端按钮级别的权限设计了解过,却还没具体实现过,最近项目打算对权限进行细分,先研究下前端的权限吧。

权限设计的出发点在于,让不同权限的用户,看到的内容、可实现的操作是不同的。

到具体设计上来说,可以分为路由级权限和按钮级权限,从实现的难以层度上来说,都挺简单的,这篇博客主要讲按钮级别的权限控制。

按钮级权限需要做的是什么?

做权限控制,首先要知道要实现的目的是什么。

按钮级权限控制比较简单,根据身份不同,可以看到的按钮、可操作的功能也不相同。

首先要进行身份的区分和校验,可根据服务端下发的用户权限类别,提取出公共方法。

// ../utils/auth.js 文件位置


//获取当前客户权限
export function getCurrentAuthority(){
    ...
    return ["admin"]
}

//校验权限
export function check(authority = []){
    let current = getCurrentAuthority();
    return current.some(item=>item.includes(item))
}

//登录校验
export function isLogin(){
    const current = getCurrentAuthority();
    return current && current[0] !== "guest";    
}
复制代码

两种实现方法

抽离出公共方法进行身份提取和校验后,在不同的组件中就可以使用了,最粗暴的方法,就是直接使用 v-if 来进行疯狂的判断。

但是这种方法不优雅,而且会对原有就使用 v-if 的内容造成困扰,因此可以将权限判断进行使用上的封装,主要有两种方法,一是组件,二是指令。

1. 组件方式

既然 v-if 不太优雅,那么是否可以将 v-if 的功能封装呢,答案当然是可行的,我们只需要在需要权限控制的内容外部再嵌套上一层组件,通过外层组件来判断内层组件是否渲染,就可以实现我们所需要的 v-if 的能力。

关于这个权限组件,我们可以进行思考下。

首先,权限组件并不需要有具体的 dom 渲染,它的作用只是根据条件来判断是否来渲染它嵌套的具体业务组件。这样的话,它可以不具备 template 模板内容,只需要具体逻辑即可,这样它可以只是纯粹的函数式组件,通过引用封装好的权限校验方法,来判断props中所允许的权限。

扫描二维码关注公众号,回复: 13470813 查看本文章

组件实现:

<script>
import { check } from "../utils/auth.js";

export default {
    name: 'Authorized',
    functional:true,
    props: {
        authority:{
            type:Array,
            required:true
        }
    },  
    render(h, context) {
        const { props, scopedSlots } = context;
        return check(props.authority) ? scopedSlots.default() : null
    },
}
</script>
复制代码

思路:

通过 props 传递允许的权限,在 render 函数中,通过上下文取出 props 和 slot 插槽内容,通过 check 方法校验 props 传递的权限是否通过,根据结果渲染 slot 的内容,实现权限控制。

组件使用:

<template>
    <Authorized :authority="['admin']" >
        <other-components></other-components>
    </Authorized>
</template>
复制代码

注:Authorized 组件会在多个地方使用,可以进行全局注册,具体代码不展示

2.指令方式

使用组件方式进行权限控制,基本已经可以很好的满足我们实现按钮级权限控制的需求了,只需要在需要控制权限的按钮外面添加组件。

不过每次都需要在外面嵌套组件,还是比较繁琐的,我们可以参考下 v-if 进行自定义指令控制。

//./directives/auth.js
import { check } from '../utils/auth.js';

function install(Vue, options = {}) {
    Vue.directive(options.name || 'auth', {
        inserted(el, binding) {
            if (!check(binding.value)) {
                el.parentNode && el.parentNode.removeChild(el);
            }
        }
    })
}

export default { install }
复制代码

思路:

接收自定义指令 binding 中传递的参数,通过 check 函数进行校验,校验未通过时,获取当前指令所在节点的父节点,来删除掉当前节点,实现权限控制。

指令注册:

// main.js
import auth from './directives/auth.js'

Vue.use(auth)
复制代码

指令使用:

<template>
	<other-components v-auth="['admin']"></other-components>
</template>
复制代码

优缺点

使用组件方式来实现权限控制,在权限修改后会比较灵活的渲染受控部分,同时使用时候会稍微繁琐;

指令方式实现的权限控制,使用起来会比较简洁,但是是通过删减 dom 节点的方式实现的,因此只有在第一次时控制。

权限在赋予后,不会随意变动,可以根据使用场景来选用两种不同的方式。

相关资料

1. Vue 函数式组件

2. 自定义指令

猜你喜欢

转载自juejin.im/post/6979530577317740551