vue tree封装一个可选的树组件方式
作者:秋刀鱼笛滋味 发布时间:2024-05-09 09:53:59
标签:vue,tree,封装,树组件
组件实现的基本功能
1,根据后端返回的数据格式,传入组件动态的渲染出当前角色有哪些权限(新建,修改)
2,适配有2级和只有一级多选的数据
3,有全选(√) ,全不选 ,部分已选(-)的3装状态,每一级都支持(用的iview2次封装)
4,改变之后返回当前选中的所有权限的id,用于提交
5,手风琴效果,小屏适配
先看效果图
有部分权限没打开
打开
小屏
权限数据结构,select_status=1表示选中
默认添加没有权限的初始数据结构
有些数据只有一级子菜单,有些有两级
核心代码.vue
<template>
<div class="powerList">
<div v-for="(item,index) in powers" :key="item.id" :class="{item:true,active:item.active}">
<Checkbox :indeterminate="item.indeterminate" :value="item.val1" @click.prevent.native="handleCheckAll(index)">
<span style="color:#1C213A;font-weight:600;"> {{item.name}}</span>
</Checkbox>
<div style="font-size:30px;float:right;width:220px;cursor: pointer;color:#BEC1C8;text-align:right;" @click="open(item.active,index)">
<Icon :type="item.active? 'md-arrow-dropup': 'md-arrow-dropdown'" />
</div>
<!-- 全部都是只有一级子菜单的 -->
<CheckboxGroup v-if="oneChild(item.child)" v-model="item.checked" @on-change="checkGroupChange($event,index)">
<Checkbox v-for="item2 in item.child" :key='item2.id' :label="item2.id">{{item2.name}}</Checkbox>
</CheckboxGroup>
<template v-else>
<div v-for='(item3,index3) in item.child' :key="item3.id" class="item3">
<!-- 有二级子菜单的 -->
<template v-if="item3.child">
<Checkbox :indeterminate="item3.indeterminate" :value="item3.val1" @click.prevent.native="level2CheckAll(index,index3)"> {{item3.name}}</Checkbox>
<CheckboxGroup v-model="item3.checked" @on-change='checkGroupChange($event,index,index3)'>
<Checkbox v-for="item4 in item3.child" :key='item4.id' :label="item4.id">{{item4.name}}</Checkbox>
</CheckboxGroup>
</template>
</div>
</template>
</div>
</div>
</template>
<script>
/**
*公共的权限选择组件,接受后端返回的权限列表powerData
*返回选中的权限的id的arr @change接受
*/
export default {
props: {
powerData: Array
},
data () {
return {
powers: []
}
},
watch: {
powerData: {
handler (val, old) {
if (val && val.length && JSON.stringify(val) !== JSON.stringify(old)) {
this.powers = this.formatData(val)
this.save([...this.powers])
}
},
immediate: true,
deep: true
}
},
methods: {
// 保存返回选中的项的数组
save (arr) {
let auth_id = []
arr.forEach(item => {
if (item.indeterminate || item.val1) {
auth_id.push(item.id)
if (this.oneChild(item.child)) {
auth_id = auth_id.concat([...item.checked])
} else {
item.child.forEach(item2 => {
if (item2.indeterminate || item2.val1) {
auth_id.push(item2.id)
auth_id = auth_id.concat([...item2.checked])
}
})
}
}
})
console.log(auth_id)
this.$emit('change', auth_id)
},
//把获取到的权限格式化成需要的格式
/**
* active :dom开关
* indeterminate: 勾选状态为-的样式
* val1 全选的状态
* total 有多级时子菜单的总数
* checked 二级多选当前选中的值
*/
formatData (arr) {
return arr.map(item => {
item.active = false //用于开关下拉
if (!this.oneChild(item.child)) { // 有多级子菜单
let total = 0 //计算当前项下的底级子菜单的总数 用于给主一级全选相应的状态
item.child.map(item => item.child.length).forEach(item => {
total += item
})
item.total = total
item.child = item.child.map(item2 => {
item2.checked = item2.child.filter(item3 => item3.select_status === 1).map(item4 => item4.id)
if (item2.checked.length === item2.child.length) { //选中的子选项数量等于子选项数量 就是全选
item2.indeterminate = false
item2.val1 = true
} else if (item2.checked.length === 0) { // 没有选中的
item2.indeterminate = false
item2.val1 = false
} else { //<
item2.indeterminate = true
item2.val1 = false
}
return item2
})
this.changeLevel1Status(item) // 设置一级全选的状态
} else { // 只有一级子菜单的
item.checked = item.child.filter(item => item.select_status === 1).map(item => item.id) //子菜单当前选中的值
let childNum = item.child.length
let checkedNum = item.child.filter(item5 => item5.select_status === 1).length
if (checkedNum === 0) {
item.indeterminate = false
item.val1 = false
} else if (checkedNum < childNum) {
item.indeterminate = true
item.val1 = false
} else {
item.indeterminate = false
item.val1 = true
}
}
return item
})
},
// 权限展开,手风琴
open (val, index) {
// 关闭所有的
this.powers = this.powers.map(item => {
item.active = false
return item
})
let obj = this.powers[index]
obj.active = !val
// 打开点击的
this.powers.splice(index, 1, obj)
},
// 只有一级子菜单的
oneChild (arr) {
return arr.every(item => item.child === undefined)
},
/**
* 主菜单的全选
* @param index (索引)
*/
handleCheckAll (index) {
if (this.oneChild(this.powers[index].child)) { //只有一级子菜单的
let powers = [...this.powers]
let obj = powers[index]
if (obj.indeterminate) { //当前项有子菜单选中的
obj.val1 = false;
} else {
obj.val1 = !obj.val1
}
obj.indeterminate = false;
if (obj.val1) { // 如果是全选
obj.checked = obj.child.map(item => item.id);
} else {
obj.checked = [];
}
this.powers = [...powers]
this.save([...this.powers])
} else {
this.checkAllOther(index)
}
},
// 有多级子菜单的全选
checkAllOther (index) {
let powers = [...this.powers]
if (powers[index].indeterminate) { //当前项有子菜单选中的
powers[index].val1 = false;
} else {
powers[index].val1 = !powers[index].val1
}
powers[index].indeterminate = false;
if (powers[index].val1) { // 如果是全选
powers[index].child.forEach(item => {
item.val1 = true // 所有2级全选选中
item.indeterminate = false //状态去掉
item.checked = item.child.map(item2 => item2.id) //2级全选的子菜单都选中
})
} else {
powers[index].child.forEach(item => {
item.val1 = false
item.checked = [];
item.indeterminate = false //状态去掉
})
}
this.powers = [...powers]
this.save([...this.powers])
},
// 子菜单的checkGrounp改变,data选中的项的id构成的arr
checkGroupChange (data, index, index3) {
let powers = [...this.powers]
let obj = index3 === undefined ? powers[index] : powers[index].child[index3]// 有index3就是二级子菜单的checkGroup
if (data.length === obj.child.length) { //全部勾选
obj.indeterminate = false;
obj.val1 = true;
} else if (data.length > 0) { //有选中的
obj.indeterminate = true;
obj.val1 = false;
} else { //没选中的
obj.indeterminate = false;
obj.val1 = false;
}
// 有二级子菜单的项改变的时候
if (index3 !== undefined) {
this.changeLevel1Status(powers[index])
}
this.powers = [...powers]
this.save([...this.powers])
},
// 2级的全选
level2CheckAll (index, index3) {
let powers = [...this.powers]
let obj = powers[index].child[index3] //当前操作的2级全选
if (obj.indeterminate) { //当前项有子菜单选中的
obj.val1 = false;
} else {
obj.val1 = !obj.val1
}
obj.indeterminate = false;
if (obj.val1) { // 如果是全选
obj.checked = obj.child.map(item => item.id);
} else {
obj.checked = [];
}
this.changeLevel1Status(powers[index])
this.powers = [...powers]
this.save([...this.powers])
},
// 二级子菜单或2级全选时更改一级全选的状态
changeLevel1Status (obj) {
let checkedNum = 0
obj.child.map(item => item.checked.length).forEach(item => {
checkedNum += item
})
if (checkedNum === 0) {
obj.indeterminate = false
obj.val1 = false
} else if (checkedNum < obj.total) {
obj.indeterminate = true
obj.val1 = false
} else {
obj.indeterminate = false
obj.val1 = true
}
}
},
}
</script>
<style lang="scss" scoped>
.powerList {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.item {
width: 370px;
height: 58px;
background: #f9f9f9;
line-height: 58px;
margin-bottom: 20px;
padding: 0 10px 0 20px;
overflow: hidden;
&.active {
height: auto;
}
/deep/ .ivu-checkbox-group label {
display: block;
}
.item3 {
/deep/ .ivu-checkbox-group {
padding-left: 20px;
label {
display: inline-block;
}
}
}
}
}
</style>
核心代码主要就是数据的处理,底级的更改都触发上一级的状态和值得改变
用的时候主要就是一个props传入数据, 一个方法返回给父组件选中的值
<power :powerData='powers' @change="powerChange" />
以上为个人经验,希望能给大家一个参考,也希望大家多多支持asp之家。
来源:https://blog.csdn.net/weixin_43206949/article/details/88979260


猜你喜欢
- <%dim conn ’定义一个连接变量 dim&nbs
- 操作系统 : Windows 10_x64 [版本 10.0.19042.685]pjsip版本 : 2.10pjsip官网:https:/
- 方法一(只有mdf没有日志文件的可以恢复) 证明有效 1.新建同名数据库。 2.把该数据库设置为脱机。 3.删除其日志文件(.LDF),不删
- webpack的loaders是一大特色,也是很重要的一部分。这遍博客我将分类讲解一些常用的laoder一、loaders之 预处理css-
- 现在做的一个小项目需要用到python的相关知识,但是因为太久没用一些东西都忘掉了,因此在本篇博客中记录一下python的函数和类的基础知识
- 页面上有些重要内容需要提醒客户,可采用的方法有很多。提醒用户关注某一区域(div),可以给该div加上边框闪烁的效果,达到吸引用户眼球的效果
- vue-property-decorator这个组件完全依赖于vue-class-component.它具备以下几个属性:@Componen
- K近邻法是有监督学习方法,原理很简单,假设我们有一堆分好类的样本数据,分好类表示每个样本都一个对应的已知类标签,当来一个测试样本要我们判断它
- ORM简介ORM概念对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在
- 覆盖原型//囚犯示例 //1.定义原型对象 var proto = { sentence : 4, //监禁年限 probation:
- $(function(){ var handler = function(){ } var timer = setInterval( han
- 如何生成斐波那契數列斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到。用计
- 最近在学习tensorflow框架,在ubuntu下用到python的一个ide --spyder,以下是常用快捷键Ctrl+1:注释/撤销
- 升序import pandas as pdimport numpy as npdata = np.random.randint(low=2,
- 对于所有的需求,当你不知道怎么处理的时候,你就先用最简单的方法,或者说的明白一点,用最原始的方法,先实现业务需求再说。一、对提现队列数据表“
- 什么是命令行参数?命令行参数是在运行时给予程序/脚本的标志。它们包含我们程序的附加信息,以便它可以执行。并非所有程序都有命令行参数,因为并非
- 概述从今天开始, 小白我将带领大家一起来补充一下 数据库的知识.条件查询我们可以使用关键词Where来指定条件, 用于插入, 修改删除或者查
- 前言MySQL性能优化是一个老生常谈的问题,无论是在实际工作中还是面试中,都不可避免遇到相应的场景,下面博主就总结一些能够帮助大家解决这个问
- “选项卡”经常会被混同为“滑动门”,滑动门只是一种背景自适应内容的实现方法,不只可以应用在导航菜单,一样也可以应用在其他地方。例如选项卡中就
- 1、epochKeras官方文档中给出的解释是:“简单说,epochs指的就是训练过程接中数据将被“轮”多少次”(1)释义:训练过程中当一个