介绍一种vue添加按钮级权限

时代在变化

  1. 按钮级权限建议按照这种方式走:以自定义指令的形式,简单快捷粗暴。
  2. 自定义指令形式目前我理解的有两种模式:
  3. 第一种模式为权限不跟角色挂钩(前端自己控制):执行v-power=“xxxxx”
  4. 第二种模式为权限跟角色挂钩;一切权限全靠配置,在页面内需要权限的按钮只需要执行(假设我们设置自定义指令为v-power)v-power就行了。

新款权限组件

第一种权限:自定义传值校验是否有权限(如果之前使用的本文权限可直接复制以下代码增加指令就行了)

  1. 自定义指令;(然后main.js引入)
import Vue from 'vue';
import store from '@/store';

/**权限指令**/
Vue.directive('power', {
	bind: function (el, binding, vnode) {
		// 获取页面按钮权限;
		const powerList = store.getters['user/power'][vnode.context.$route.fullPath].map((v) => v.buttonName);
		if (!powerList.includes(binding.value)) {
			// 这块等待页面加载出来后去删除节点
			vnode.context.$nextTick(() => {
				el.parentNode && el.parentNode.removeChild(el);
			})
		}
	}
});
  1. 接口返回参数(与路由相对应,本文以hash来举例子的)
	power: {
      '/goods/detail': [
        {
          buttonName: 'search',
        },
        {
          buttonName: 'edit',
        },
        {          
          buttonName: 'delete',
        },
        {
          buttonName: 'export',
        }
      ]
    }
  1. vuex代码
// axios 的接口封装;测试的时候可不用。以下数据支持测试。
import { funcButtonList } from '@/api/user.js'
export default {
  // vuex 开启命名空间模式。方便使用mapGetters('user', { powers: 'power' });我这里界面名字是user.js;
  namespaced: true,
  state: {
  	// 初始测试数据
    power: {
      '/goods/detail': [
        {
          buttonName: 'search',
        },
        {
          buttonName: 'edit',
        },
        {          
          buttonName: 'delete',
        },
        {
          buttonName: 'export',
        }
      ]
    }
  },
  mutations: {
    updatePower(state, d) {
        state.power = d
    }
  },
  actions: {
    funcButtonList({commit}) {
      funcButtonList().then(({data})=> {
        commit('updatePower', data)
      })
    }
  },
  // 让 power 变为可监听的(方便 watch )
  getters: {
    power: state => state.power
  }
}
  1. 使用
    <el-button v-power="'export'">导出</el-button>
    <el-button v-power="'search'">查询</el-button>

第二种权限:跟角色挂钩模式【我自己项目不适用于跟角色挂钩,所以说我使用的是另一种】

  1. 自定义指令代码
import Vue from 'vue';

/**权限指令**/
Vue.directive('power', {
  bind: function (el, binding, vnode) {
      // 获取页面按钮权限
      let btnPermissionsArr = [];
      if(binding.value){
          // 如果指令传值,获取指令参数,根据指令参数和当前登录人按钮权限做比较。
          btnPermissionsArr = Array.of(binding.value);
      }else{
          // 否则获取路由中的参数,根据路由的btnPermissionsArr和当前登录人按钮权限做比较。
          btnPermissionsArr = vnode.context.$route.meta.btnPermissions;
      }
      if (!Vue.prototype.$_powe(btnPermissionsArr)) {
          el.parentNode.removeChild(el);
      }
  }
});
  1. 挂载在vue原型上的方法($_power
import Vue from 'vue'

Vue.prototype.$_power = function (value) {
  let isExist = false;
  // 获取用户按钮权限
  let btnPermissionsStr = sessionStorage.getItem("btnPermissions");
  if (btnPermissionsStr == undefined || btnPermissionsStr == null) {
      return false;
  }
  if (value.indexOf(btnPermissionsStr) > -1) {
      isExist = true;
  }
  return isExist;
};
  1. 使用
<el-button @click='handleClick' type="primary" v-power>编辑</el-button>

老旧式权限组件(不建议走了)

  1. 本文按钮级权限逻辑介绍:
	1)因为项目的页面级权限已经弄完善了,但是呢,这个时候用户又提出了需要按钮级权限。哎
	2)用户登录后去请求一个接口btnList。以每个页面的路由路径为key,值为这个页面的所有按钮级权限
	3)此时咱们就可以在各个页面或者组件里面判断  查询、编辑、添加、删除(crud)等权限了
	4)需要用到的有 vuex,provide-inject【重新渲染】,mixin
  1. 接口返回参数
	power: {
      '/goods/detail': [
        {
          buttonName: 'search',
        },
        {
          buttonName: 'edit',
        },
        {          
          buttonName: 'delete',
        },
        {
          buttonName: 'export',
        }
      ]
    }
  1. vuex代码
// axios 的接口封装;测试的时候可不用。以下数据支持测试。
import { funcButtonList } from '@/api/user.js'
export default {
  // vuex 开启命名空间模式。方便使用mapGetters('user', { powers: 'power' });我这里界面名字是user.js;
  namespaced: true,
  state: {
  	// 初始测试数据
    power: {
      '/goods/detail': [
        {
          buttonName: 'search',
        },
        {
          buttonName: 'edit',
        },
        {          
          buttonName: 'delete',
        },
        {
          buttonName: 'export',
        }
      ]
    }
  },
  mutations: {
    updatePower(state, d) {
        state.power = d
    }
  },
  actions: {
    funcButtonList({commit}) {
      funcButtonList().then(({data})=> {
        commit('updatePower', data)
      })
    }
  },
  // 让 power 变为可监听的(方便 watch )
  getters: {
    power: state => state.power
  }
}
  1. 封装 filterPower 方法
import store from '@/store'
/**
 * 
 * @param {param1 url} 地址栏url参数
 * @param {param1 power} 权限列表 ['edit', 'delete', 'search' ...]
 * @param {param2 flag} 当为true的时候判断为空的情况全部默认返回,否则置空返回
 * @returns 过滤掉在当前权限列表中没有的按钮 ['edit', 'delete' ...]
 */
export const filterPower = ({
  url,
  power
}, flag = false) => power.filter(
   item =>
   // user/power 这个是读取的 getters 暴露出来的属性
   !!(store.getters['user/power'][url] ?
     store.getters['user/power'][url].filter((val) => val.buttonName === item).length :
     flag)
 )
  1. 在页面的app.vue【这个得看你,我自己加到app那个最顶级要出问题,所以说我加到app子级的】添加 能让页面重新加载的方法
    1)这里有两种情况可以考虑使用,我自己选的provide+inject方法
    2)第一种是添加一个空白页面的路由,然后那个页面里面开始创建的时候(created里面写如果效果不好则改为data函数里面)写入this.$router.replace(xxxx)替换当前路由回之前路由
    3)provide+inject
    4)为什么要这个呢?因为是为了兼容用户刷新页面后重新渲染当前页面的按钮(无权限,按钮不显示出来)

    以下js代码为你的父级页面(你要确保这个v-if不会让你进入死循环【重复请求按钮权限接口】的父级页面,provide可以任意往父级套,引用的时候只会找最近的一个provide)

<template>
  <div>
     <router-view v-if="isRouterAlive"></router-view>
  </div>
</template>

<script>
  import { mapActions } from 'vuex'
  export default {
    name: "xxxx",
    provide() {
      return {
        reload: this.reload
      }
    },
    data() {
      return {
        isRouterAlive: true,
      }
    },
    created() {
	  // 请求按钮权限接口-页面刷新则去调用vuex中actions的funcButtonList方法
	  // 防止用户刷新界面权限按钮消失bug
      this.funcButtonList()
	},
    methods: {
      ...mapActions('user', ['funcButtonList']),
      reload() {
        this.isRouterAlive = false;
        this.$nextTick(()=> {
          this.isRouterAlive = true
        })
      }
    }
  }
</script>

  1. mxin封装的方法 @/mixin/power.js
import { mapGetters } from "vuex";
export default {
  inject: ['reload'],
  computed: {
  	// 这个看不懂的去看看vuex的命名空间下mapGetters写法
    ...mapGetters('user', {
      powers: 'power'
    })
  },
  watch: {
    powers() {
      // 重新加载 - 看不懂这个 去看看vue的provide和inject
      this.reload()
    }
  },
}
  1. 到了此时准备工作已经做完了,正式开工,以下为一个组件页面改出来的0.0,功能目测没问题
    主要是两步,一个引入mixin 监听接口请求刷新页面,然后就是filterPower 过滤出当前页面涵盖的功能了
<template>
  <el-row class="param-search" v-if="isShow">
  	<!-- xxxxxx-->
    <el-col :span="4" class="flex-acenter" style="justify-content: flex-end">
      <el-button
        type="primary"
        v-if="btnPower.includes('search')"
        >查询</el-button
      >
      <el-button
        type="primary"
        v-if="btnPower.includes('export')"
        >导出</el-button
      >
    </el-col>
  </el-row>
</template>

<script>
import PowerMixin from '@/mixin/power.js'
export default {
  // 这个是负责刷新时候界面更新
  mixins: [PowerMixin],
  inject: ["tableInfo"],
  data() {
    return {
      btnPower: [],
    };
  },
  computed: {
    isShow() {
      return !!this.btnPower.length
    }
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      // 初始化按钮级权限-this.$lh.filterPower 我把filterPower挂载在自己的方法上面的,这里你们自己引用上面的那个函数吧。或者跟我一起挂载在vue原型上面(下面会介绍)
      this.btnPower = this.$lh.filterPower({
        url: this.$route.path,
        power: ["search", "export"],
      });
    },
  },
};
</script>
  1. 按文件夹的形式读取挂载到vue的原型上,首先创建一个libs文件夹,再在libs中创建一个vuePrototype文件夹
    在这里插入图片描述

此处为 main.js 文件地址(vue唯一的入口文件)

import Vue from 'vue'

// 会默认直接读取文件夹内所有的js文件 (记住 使用 export default;不然你自己改下面代码去。下面取的是的value.default)
const modulesFiles = require.context('@/libs/vuePrototype', true, /\.js$/)
modulesFiles.keys().reduce((modules, modulePath) => {
  const name = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[name] = value.default
  Vue.prototype[name] = modules[name]
  return modules
}, {})

new Vue({
  render: h => h(App),
  data: {
    eventHub: new Vue()
  }
}).$mount('#app');

  1. $lh.js代码
import { filterPower } from '@/libs/power.js'
export default { filterPower }

有更好的见解,咱们交流交流哇

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,作为 AI 语言模型,我无法提供您所需的代码。但是,我可以为您提供一些提示和建议,以帮助您实现按按钮别的权限控制。 1. 定义权限 首先,您需要定义每个按钮权限。这可以通过在代码中定义常量或枚举来实现。例如: ``` const PERMISSIONS = { VIEW: 'view', EDIT: 'edit', DELETE: 'delete', }; ``` 2. 检查权限渲染按钮时,您需要检查当前用户是否有足够的权限来查看或操作该按钮。您可以将用户的权限列表保存在状态中,并在需要时进行比较。例如: ``` <template> <button v-if="hasPermission(PERMISSIONS.EDIT)">Edit</button> </template> <script> export default { data() { return { userPermissions: [PERMISSIONS.VIEW, PERMISSIONS.EDIT], }; }, methods: { hasPermission(permission) { return this.userPermissions.includes(permission); }, }, }; </script> ``` 在上面的示例中,我们使用了 `hasPermission` 方法来检查当前用户是否具有编辑权限。如果是,则渲染编辑按钮。 3. 动态生成按钮 您还可以根据用户的权限动态生成按钮。这样,只有用户具有足够的权限时,才会看到按钮。例如: ``` <template> <div> <button v-if="hasPermission(PERMISSIONS.VIEW)">View</button> <button v-if="hasPermission(PERMISSIONS.EDIT)">Edit</button> <button v-if="hasPermission(PERMISSIONS.DELETE)">Delete</button> </div> </template> <script> export default { data() { return { userPermissions: [PERMISSIONS.VIEW, PERMISSIONS.EDIT], }; }, methods: { hasPermission(permission) { return this.userPermissions.includes(permission); }, }, }; </script> ``` 在上面的示例中,我们动态生成了三个按钮。只有用户具有查看和编辑权限时,才会看到这两个按钮。 4. 使用路由守卫 最后,您还可以使用路由守卫来限制用户访问某些页面或视图。这是一种更加强大和细粒度的权限控制方式。例如: ``` const routes = [ { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true, permissions: [PERMISSIONS.VIEW], }, }, { path: '/users', component: Users, meta: { requiresAuth: true, permissions: [PERMISSIONS.VIEW, PERMISSIONS.EDIT, PERMISSIONS.DELETE], }, }, ]; router.beforeEach((to, from, next) => { const isAuthenticated = store.getters.isAuthenticated; const requiresAuth = to.matched.some(record => record.meta.requiresAuth); if (requiresAuth && !isAuthenticated) { next('/login'); } else { const userPermissions = store.getters.userPermissions; const requiredPermissions = to.matched.reduce((acc, record) => { if (record.meta && record.meta.permissions) { acc.push(...record.meta.permissions); } return acc; }, []); const hasPermission = requiredPermissions.every(permission => userPermissions.includes(permission) ); if (hasPermission) { next(); } else { next('/403'); } } }); ``` 在上面的示例中,我们使用路由守卫来检查用户是否已经通过身份验证,并且是否具有访问当前路由所需的权限。如果用户没有通过身份验证或没有足够的权限,则重定向到适当的页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值