vue?tree封裝一個可選的樹組件方式
組件實現(xiàn)的基本功能
1,根據(jù)后端返回的數(shù)據(jù)格式,傳入組件動態(tài)的渲染出當前角色有哪些權限(新建,修改)
2,適配有2級和只有一級多選的數(shù)據(jù)
3,有全選(√) ,全不選 ,部分已選(-)的3裝狀態(tài),每一級都支持(用的iview2次封裝)
4,改變之后返回當前選中的所有權限的id,用于提交
5,手風琴效果,小屏適配
先看效果圖
有部分權限沒打開

打開

小屏

權限數(shù)據(jù)結(jié)構(gòu),select_status=1表示選中

默認添加沒有權限的初始數(shù)據(jù)結(jié)構(gòu)

有些數(shù)據(jù)只有一級子菜單,有些有兩級
核心代碼.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: {
// 保存返回選中的項的數(shù)組
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: 勾選狀態(tài)為-的樣式
* val1 全選的狀態(tài)
* total 有多級時子菜單的總數(shù)
* checked 二級多選當前選中的值
*/
formatData (arr) {
return arr.map(item => {
item.active = false //用于開關下拉
if (!this.oneChild(item.child)) { // 有多級子菜單
let total = 0 //計算當前項下的底級子菜單的總數(shù) 用于給主一級全選相應的狀態(tài)
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) { //選中的子選項數(shù)量等于子選項數(shù)量 就是全選
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) // 設置一級全選的狀態(tài)
} 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 //狀態(tài)去掉
item.checked = item.child.map(item2 => item2.id) //2級全選的子菜單都選中
})
} else {
powers[index].child.forEach(item => {
item.val1 = false
item.checked = [];
item.indeterminate = false //狀態(tài)去掉
})
}
this.powers = [...powers]
this.save([...this.powers])
},
// 子菜單的checkGrounp改變,data選中的項的id構(gòu)成的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級全選時更改一級全選的狀態(tài)
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>
核心代碼主要就是數(shù)據(jù)的處理,底級的更改都觸發(fā)上一級的狀態(tài)和值得改變
用的時候主要就是一個props傳入數(shù)據(jù), 一個方法返回給父組件選中的值
<power :powerData='powers' @change="powerChange" />
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue中子組件向父組件傳遞數(shù)據(jù)的實例代碼(實現(xiàn)加減功能)
這篇文章主要介紹了vue中子組件向父組件傳遞數(shù)據(jù)的實例代碼(實現(xiàn)加減功能) ,需要的朋友可以參考下2018-04-04
vue-devtools?開發(fā)工具插件之支持vue3?chrome?瀏覽器插件
這篇文章主要介紹了vue-devtools?開發(fā)工具插件之支持vue3?chrome?瀏覽器插件,用這個版本主要是為了支持vue3?推薦直接下載,文中給大家提供了下載地址,感興趣的朋友跟隨小編一起看看吧2022-01-01
詳解vue-cli之webpack3構(gòu)建全面提速優(yōu)化
這篇文章主要介紹了詳解vue-cli之webpack3構(gòu)建全面提速優(yōu)化,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12

