vue权限按钮的实现

news2024/11/24 17:45:02

鉴权函数

由于下面几种方式都需要用到鉴权函数,所以将其放置在组件外面,供组件或其他文件调用。

// src/utils/hasPermission.js

import { usePermissionStore } from '@/stores'
import array from 'lodash/array'
export const hasPermission = (value, def = true) => {
  // 不传值,默认视为有权限,不做鉴权
  if (!value) {
    return def
  }

  const allCodeList = usePermissionStore().getPermCodeList
  // 如果不是数组,直接判断pinia里的权限数组有没有相同的元素即可
  if (!Array.isArray(value)) {
    return allCodeList.includes(value)
  }
  // intersection是lodash提供的一个方法,用于返回一个所有给定数组都存在的元素组成的数组
  return array.intersection(value, allCodeList).length > 0
}

将可以操作按钮的权限码们以权限码数组的形式存放到了pinia中,所以要先获取pinia中的权限数组再进行判断。

  1. 情况一:没有传值,则无法做权限码的比对,所以可以认为不需要鉴权,返回true即可。
  2. 情况二:传入的值是权限码数值,不是数组,那么可以拿pinia中的权限码数组来检测是否包含该权限码,如果有则认为有权限返回true;否则返回false。
  3. 情况三:传入的值是权限码数组,此时需要拿传入的数组和pinia中的权限码数组进行比较,看看是否存在交集,如果有交集则说明有权限,返回true;否则返回false。

Pinia:

// store/index.js

import { createPinia } from "pinia";

const pinia=createPinia()

export default pinia

export  * from './modules/permission.js'
// store/modules/permission.js

import { defineStore } from 'pinia'
import { getPermissionList } from '@/api/permission'
export const usePermissionStore = defineStore('permission', {
  state: () => ({
    // 权限代码列表
    permCodeList: [101, 102, 778, 779]
  }),
  getters: {
    // 获取
    getPermCodeList() {
      return this.permCodeList
    }
  },
  actions: {
    // 存储
    setPermCodeList(codeList) {
      this.permCodeList = codeList
    },

    // 请求权限码
    async getPermissionCode() {
      const codeList = await getPermissionList()
      this.setPermCodeList(codeList)
    }
  }
})

方式一:v-if搭配鉴权函数实现权限按钮

引入鉴权函数,将该能够操作该按钮的权限码以实参形式传入鉴权函数,v-if根据返回值决定是否加载该按钮结构。

<template>
  <div>
    <button class="fun-btn" v-if="hasPermission([101])">你能看到我?-v-if函数实现</button>
  </div>
</template>

<script setup>
import { hasPermission } from '@/utils/hasPermission'
</script>

<style scoped lang="scss"></style>

方式二:组件+插槽 实现权限按钮

将按钮以插槽形式放入组件中,给组件以props传递权限码数据,组件中使用鉴权函数来判断传入的权限码是否符合条件,符合则渲染插槽中的结构(按钮),否则不渲染。

<!--components/PermisBtnComp.vue-->
<template></template>

<script>
// h函数  https://cn.vuejs.org/api/render-function.html#h
// defineComponent-函数签名 https://cn.vuejs.org/api/general.html#definecomponent
import { hasPermission } from '@/utils/hasPermission'
import { renderSlot, h, defineComponent } from 'vue'

export default defineComponent({
  props: {
    value: {
      type: [Number, String, Array],
      default: ''
    }
  },
  setup(props, { slots }) {
    return () => {
      // 根据权限判断结果来确定是否要渲染默认插槽的结构
      // 在 Vue 3 中,通过 renderSlot(父组件传入的插槽内容,插槽名) 函数进行插槽渲染时,需要将其导入并包含在组件的 setup 方法中。
      // 父组件引用子组件时,子组件标签内的默认内容对应的是:renderSlot(slots, 'default')
      // return hasPermission(props.value) ? h('div', renderSlot(slots, 'default')) : null

      // 免去renderSlot https://cn.vuejs.org/guide/extras/render-function.html#rendering-slots
      return hasPermission(props.value) ? h('div', slots.default()) : null
    }
  }
})
</script>

<style scoped lang="scss"></style>

方式三:自定义指令 实现权限按钮

自定义指令其实和第一种很像,就是我们自己出一个"v-if",只不过是专门用来做权限判断的指令。指令传入的数据即为权限码,指令内部根据指令绑定的数据来做鉴权判断。

注意点1:这里的mounted可能较容易实现,但需要注意updated的设计,考虑到有动态修改指令后面的权限码的可能,所以当涉及到指令后面的权限码修改后,要重新做鉴权判断。

注意点2:自定义指令在内部的鉴权判断后,如果不符合条件要移除指令所在的结构;如果符合条件的话,要把之前因为不符合条件被移除的结构要添加回来,也就是回添操作;回添操作为了避免不知道把原来的结构添加回来到哪个位置,这里使用了document.createComment() 即注释先做占位,等需要回添时使用replaceChild() 把注释替换为按钮结构。如果使用的是remove()removeChild()可能再放回来就不知道放到哪个位置了。

// src/directs/judge-permission.js

import { hasPermission } from '@/utils/hasPermission'

// removeDom、addDom的存在是为了保证自定义指令绑定的权限码数据变化后可以不刷新页面动态添加/移除自定义指令所在的dom节点
// 移除dom节点
const removeDom = (el) => {
  // 把注释点绑在元素上,方便后面使用
  el._placeholderNode = document.createComment('permission-btn')
  // 和父节点关联上,方便后面使用
  el._parentNode = el.parentNode
  // 父节点做子元素替换
  el.parentNode.replaceChild(el._placeholderNode, el)
}

// 把移除的dom节点添加回来
const addDom = (el) => {
  el._parentNode?.replaceChild(el, el._placeholderNode)
}

const mounted = (el, binding) => {
  const permisList = binding.value
  if (!permisList) return
  if (!hasPermission(permisList)) {
    // 移除当前dom节点
    // el.parentNode?.removeChild(el) // 通过父节点删除子自己
    // el.remove() // 自杀
    /* 
        权限值会变,那就涉及到更新后要不要将移除的dom节点添加回来
        为了能够知道添加回来的dom节点放到哪个地方,可以创建注释节点来占位
        在添加时只对那个位置的子元素做替换操作即可
    */
    removeDom(el)
  }
}

const updated = (el, binding) => {
  // 比对前后变化的值,相同不需要后续操作
  let valDiff = binding.value === binding.oldValue
  if (valDiff) return
  // 重新判断改值前后的权限变化,相同不需要后续操作(如:修改前就没权限,修改后依旧没权限,无需操作)
  let oldPermisStatus = hasPermission(binding.oldValue)
  let nowPermisStatus = hasPermission(binding.value)

  if (oldPermisStatus == nowPermisStatus) return
  if (nowPermisStatus) {
    addDom(el)
  } else {
    removeDom(el)
  }
}

export const permisDirect = {
  mounted,
  updated
}

main.js中添加指令:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import pinia from './stores'
import {permisDirect} from '@/directs/judge-permission'

const app=createApp(App)
app.use(pinia)
app.directive('permis',permisDirect)
app.mount('#app')

根组件效果展示

<script setup>
import PermisBtnFun from './components/PermisBtnFun.vue'
import PermisBtnComp from './components/PermisBtnComp.vue'
import { ref } from 'vue'

const permis = ref(102)
const permisToggle = () => {
  // 由于@/utils/hasPermission中有判断!value则返回true,表示没传值默认不需要鉴权,返回true放行
  // 所以这里在调整权限值的时候不能改成0,因为!0==true,如果变化前就有权限(true),变化后想没权限改为0,刚好!0是true,弄巧成拙,依旧显示。
  permis.value === 102 ? (permis.value = 100) : (permis.value = 102)
}
</script>

<template>
  <div class="btns-container">
    <!-- v-if搭配函数方式 -->
    <PermisBtnFun />
    <!-- 组件+插槽方式 -->
    <PermisBtnComp :value="101">
      <button class="comp-slot-btn">就你能耐?-组件插槽实现</button>
    </PermisBtnComp>
    <!-- 自定义指令方式 -->
    <button class="vpermis-btn" v-permis="permis">你依旧能看得到我?-自定义指令实现</button>
    <!-- 修改自定义指令绑定的权限值,测试自定义指令updated中的移除和回添的操作 -->
    <button @click="permisToggle">修改自定义指令绑定的权限值</button>
  </div>
</template>

<style scoped>
.btns-container {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  height: 400px;
}
/* ::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead. */
:deep(.fun-btn) {
  background-color: #acd384;
  color: #fff;
}
.vpermis-btn {
  background-color: #f38585;
  color: #fff;
}
.comp-slot-btn {
  background-color: #5aa3f8;
  color: #fff;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/786442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

火车头采集文章批量伪原创【php源码】

火车头采集是一款基于Python语言开发的网络爬虫工具&#xff0c;用于快速高效地从互联网上采集数据并存储到本地或远程数据库。它简单易用且功能强大&#xff0c;在各行各业广泛应用。 火车头采集器AI伪原创PHP源码&#xff1a; <?php header("Content-type: text/h…

C# WPF项目创建(基于VS 2019介绍)

1.打开VS&#xff0c;选择《创建新项目》 2.选择《WPF应用程序》&#xff0c;如图 3. 项目名称根据需求自行命名&#xff0c;这边以“WpfApp1”来命名&#xff0c;位置自行选择&#xff0c;这边选择了"E:\test"&#xff0c;如图所示&#xff0c;“将解决方案和项目…

【广州华锐互动】VR模拟灭火逃生体验系统

VR模拟灭火逃生体验系统由广州华锐互动开发&#xff0c;是一种基于虚拟现实技术的应急演练与培训系统&#xff0c;可以真实模拟消防逃生场景&#xff0c;让体验者在沉浸式的虚拟环境中&#xff0c;根据正确的消防逃生方法提示&#xff0c;进行自救演练。这种科学普及方法是更加…

datafree KD CVPR2023 学习笔记(Abstract)

这个 是摘要的前部分 摘要 简单的提及 无数据的蒸馏 是怎么样的 和普通的蒸馏有一个本质的区别&#xff1a;没有训练数据 很火啊 最近 在对抗性的蒸馏框架中呢 存在一个问题 由于多个生成器生成的 非平稳分布的pseudo-samples 导致了学生网络的性能不好 提出一个解决方案的i…

Docker——数据管理与网络通信

Docker——数据管理与网络通信 一、Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器 二、端口映射三、容器互联&#xff08;使用centos镜像&#xff09;四、Docker 镜像的创建1&#xff0e;基于现有镜像创建1.1 首先启动一个镜像&#xff0c;在容器里做修改1.2 然…

如何搭建使用dubbo-Admin?

dubbo-Admin介绍 一款用于dubbo可视化界面操作的管理平台 dubbo-Admin特点 dubbo-Admin是dubbo的管理界面平台&#xff0c;且是一个前后端分离的项目&#xff0c;前端使用vue&#xff0c;后端使用springboot。 软件下载 dubbo-admin-0.5.0.zip 软件使用

Java文件的相对路径规则

前言 最近做项目&#xff0c;又涉及到Linux Java文件的相对路径&#xff0c;但是相对路径在不同的服务器或者docker上居然不一样&#xff0c;这个就很难受&#xff0c;只能用绝对路径解决&#xff0c;因为绝对路径是固定的路径&#xff0c;但是相对路径为什么会在不同的服务器…

将pdf转换成word怎么转换?掌握这几个转换方法就够了

将pdf转换成word怎么转换&#xff1f;将 PDF 转换成 Word 文档是一个常见的需求&#xff0c;我们需要编辑 PDF 文件中的文字内容&#xff0c;但是 PDF 文件并不方便直接编辑。下面介绍几个转换方法。 方法一&#xff1a;使用迅捷 PDF 转换器 这是一款专业的 PDF 转换工具&…

【2023】HashMap详细源码分析解读

前言 在弄清楚HashMap之前先介绍一下使用到的数据结构&#xff0c;在jdk1.8之后HashMap中为了优化效率加入了红黑树这种数据结构。 树 在计算机科学中&#xff0c;树&#xff08;英语&#xff1a;tree&#xff09;是一种抽象数据类型&#xff08;ADT&#xff09;或是实作这种…

2023年深圳杯数学建模 D题 基于机理的致伤工具推断

致伤工具的推断一直是法医工作中的热点和难点。由于作用位置、作用方式的不同&#xff0c;相同的致伤工具在人体组织上会形成不同的损伤形态&#xff0c;不同的致伤工具也可能形成相同的损伤形态。致伤工具品种繁多、形态各异&#xff0c;但大致可分为两类&#xff1a;锐器&…

结构体——位段

//结构体--位段 &#xff08;位 指二进制位 &#xff09; // 位段的声明与结构体是类似的 // 1&#xff0c;位段的成员必须是 int &#xff0c;unsigned int 或 signed int // 2&#xff0c;位段的成员名后边有一个冒号和一个数字。&#xff08;数字表示开辟需要的比特位个数&a…

【【51单片机的温度识别】】

51单片机的温度识别 这么热的天&#xff0c;再离我远一点 DS18B20温度读取 温度报警 我们这里对于单总线 也仿照I2C 总线的模样 以下是我们实现的onewire.c文件 #include <REGX52.H> //第一步从原理图触发先定义端口sbit OneWire_DQP3^7;//第一步初始化unsigned char…

商城-学习整理-基础-前端(四)

目录 一、技术栈介绍二、ES61、简介2、什么是ECMAScript3、ES6 新特性1、let 声明变量2、const 声明常量&#xff08;只读变量&#xff09;3、解构表达式1&#xff09;数组解构2&#xff09;对象解构 4、字符串扩展1&#xff09;、几个新的 API2&#xff09;、字符串模板 5、函…

跨洋消息队列CKafka

背景 跨洋消息队列CKafka&#xff0c;是腾讯出品开源消息队列组件&#xff0c;为了解决客户跨地域容灾、冷备的诉求跨地域秒级准实时数据同步而开源的腾讯云中间件。 整体架构图 数据同步主要流程 Connect 集群初始化 Connect Task&#xff0c;每个 Task 会新建多个 Worker C…

3D元宇宙游戏,或许能引爆新的文娱消费增长点

从去年开始&#xff0c;在互联网上&#xff0c;一个名为【神念无界-源起山海】的元宇宙游戏项目火了。除了可以在游戏内体验独战、团队式作战等3D古风经典游戏场景和玩法&#xff0c;还有钓鱼增加能量、情侣姻缘一线牵&#xff0c;结婚等多元化逼真效果与玩法&#xff0c;这令很…

第118天:免杀对抗-二开CS上线流量特征Shellcode生成机制反编译重打包(上)

知识点 #知识点&#xff1a; 1、CS-表面特征消除 2、CS-HTTP流量特征消除 3、CS-Shellcode特征消除#章节点&#xff1a; 编译代码面-ShellCode-混淆 编译代码面-编辑执行器-编写 编译代码面-分离加载器-编写 程序文件面-特征码定位-修改 程序文件面-加壳花指令-资源 代码加载面…

opencv-21 alpha 通道详解(应用于 图像增强,合成,蒙版,特效 等)

什么是alpha 通道&#xff1f; Alpha通道是计算机图形学中用于表示图像透明度的一种通道。在一个图像中&#xff0c;通常会有三个颜色通道&#xff1a;红色&#xff08;R&#xff09;、绿色&#xff08;G&#xff09;、蓝色&#xff08;B&#xff09;&#xff0c;它们合在一起…

将Parasoft和ChatGPT相结合会如何?

ChatGPT是2023年最热门的话题之一&#xff0c;是OpenAI训练的语言模型。它能够理解和生成自然语言文本&#xff0c;并接受过大量数据的训练&#xff0c;包括用各种编程语言编写的许多开源项目的源代码。 软件开发人员可以利用大量的知识库来协助他们的工作&#xff0c;因为它具…

网络安全高级课笔记1

HTML字符编码/HTML实体编码 html实体编码 unicode urlcode 在字符的十六进制前加百分号&#xff08;%&#xff09;&#xff0c;用于浏览器的网址输入框 utf-8 字符数字表示法 HTML允许使用Nuicode码点表示字符&#xff0c;浏览器会自动将码点转成对应的字符。 字符的码点表…

vtk能否被OpenGL和DirectX取代?

VTK&#xff08;Visualization Toolkit&#xff09;是一个强大的开源可视化库&#xff0c;用于处理和呈现各种科学数据。它建立在OpenGL和DirectX等底层图形库之上&#xff0c;提供了高级的可视化功能和算法。虽然OpenGL和DirectX可以用于图形渲染和实时图形处理&#xff0c;但…