美文网首页
Vue中如何优雅的封装一个权限控制组件

Vue中如何优雅的封装一个权限控制组件

作者: 爱吃猫的老虎 | 来源:发表于2023-11-15 10:01 被阅读0次

    通常没有经验的小伙伴们对页面中一些按钮或组件进行权限控制会像以下这样:
    1.通常在vuexstore中存储用户的权限信息(一般是权限code数组,或者角色code数组)

     export default {
        name: '张三',
        token: '',
        permissions: ['DELETE_ARTICLE', 'USER_MANAGEMENT'],
    }
    

    2.在业务组件中使用mapState获取store中的用户权限信息,再在模板通过v-if判断是否有目标权限进行条件显示

    <template>
        <div>
            <h2>这是一个文章列表页面</h2>
            <el-button v-if="showDeleteButton">删除文章</el-button>
        </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    export default {
        name: 'Demo',
        computed: {
            ...mapState({
                permissions: state => state.user.permissions
            }),
            showDeleteButton() {
                return this.permissions.some(code => code === 'DELETE_ARTICLE')
            }
        },
    }
    </script>
    

    但是需要鉴权的业务组件非常多的时候,就要在每个组件里都复制一份以上的重复代码,下面针对以上现象我们封装一个鉴权组件来改善这种情况:
    1.第一步封装一个名为Auth.vue的组件,并删除template标签。

    <script>
    export default {
        name: 'Auth'
    }
    </script>
    

    2.第二步,添加render函数,并在组件中使用mapState获取用户权限信息,如果用户有权限就返回默认插槽,如果没有权限就返回null

    <script>
    import { mapState } from 'vuex'
    export default {
        name: 'Auth',
        props: {
            code: String, // 需要的权限
        },
        computed: {
            ...mapState({
                permissions: state => state.user.permissions
            })
        },
        render() {
            const { $slots, permissions, code } = this
            const hasPermission = permissions.some(p => p === code)
            return hasPermission ? $slots.default : null
        }
    }
    </script>
    

    3.第三步就可以愉快的使用了,将该组件注册到全局并在业务组件中使用

    main.js中:

    import Auth from './components/Auth'
    import Vue from 'vue'
    
    Vue.component('sl-auth',  Auth)
    

    在业务组件中使用该组件:

    <template>
        <div>
            <h2>这是一个文章列表页面</h2>
            <sl-auth code="DELETE_ARTICLE">
                <el-button>删除文章</el-button>
            </sl-auth>
        </div>
    </template>
    
    <script>
    export default {
        name: 'Demo',
    }
    </script>
    
    

    代码跟之前比精简了很多,针对以上vuex用法还可以继续优化,可以将用户权限Array换成Map的结构并放在storegetters中,转换操作一般只进行一次,单次使用时间复杂度从O(n)降低到O(1)。

    在store中:

    export default new Vuex.Store({
        modules: {
            user
        },
        getters: {
            // 用户权限Map
            getPermissionMap: state => {
                const permissions = state.user.permissions
                const permissionMap = new Map() // 创建一个空Map
                permissions.forEach(code => permissionMap.set(code, code))
                return permissionMap
            },
        }
    })
    

    然后改造Auth.vue:

    <script>
    import { mapGetters } from 'vuex'    // 这里换成mapGetters
    export default {
        name: 'Auth',
        props: {
            code: String, // 需要的权限
        },
        computed: {
            ...mapGetters(['getPermissionMap']),    // 从getters里获取权限Map
        },
        render() {
            const { $slots, getPermissionMap, code } = this
            return getPermissionMap.has(code) ? $slots.default : null    // 通过Map.has()判断是否拥有权限
        }
    }
    </script>
    

    现在鉴权组件就封装好了,查了一下资料,由于render函数中不能使用template标签做为根节点,所以在使用该鉴权组件时包裹的子元素不能是多个,错误的使用方式:

    <template>
        <sl-auth code="DELETE_ARTICLE">
            <el-button>删除文章</el-button>
            <el-button>删除文章</el-button>
        </sl-auth>
    </template>
    

    应该多次使用该组件进行包裹,正确的使用方式:

    <template>
        <sl-auth code="DELETE_ARTICLE">
            <el-button>删除文章</el-button>
        </sl-auth>
        <sl-auth code="DELETE_ARTICLE">
            <el-button>删除文章</el-button>
        </sl-auth>
    </template>
    

    (完)

    相关文章

      网友评论

          本文标题:Vue中如何优雅的封装一个权限控制组件

          本文链接:https://www.haomeiwen.com/subject/lxsswdtx.html