一.实现效果
el-cascader-panel自定义角色权限页面-平铺显示+实现菜单+按钮区分显示+输入模糊搜索+点击定位展开对应的项
<el-cascader-panel
ref="cascader"
v-model="selectedOptions"
class="cascader_panel"
:present-text="keyword"
filterable
:props="cascaderProps"
show-checkbox
:options="permissionTree"
:active-path.sync="activePath"
@change="handleCascaderChange"
>
<template slot-scope="{ node, data }">
<!-- 判断为按钮 -->
<span v-if="data.menuType === 3" style="color: #2c69d8;">{{ data.menuName }}</span>
<span v-else>{{ data.menuName }}</span>
</template>
</el-cascader-panel>
cascaderProps: {
value: 'menuId',
multiple: true, children: 'childrenMenu',
label: 'menuName',
emitPath: false,
id: 'menuId'
},
输入模糊搜索+点击定位展开对应的项
<div class="searchForm">
<el-checkbox v-model="selectCheckedAll" class="all_checkbox" @change="selectAll">全选</el-checkbox>
<div class="button">
<el-input
v-model="keyword"
clearable
placeholder="请输入菜单名称"
prefix-icon="el-icon-search"
size="small"
style="width: 500px;"
@input="handleInput"
/>
<div v-if="selectedList&&selectedList.length && showselectedList" class="autocomplete_list">
<div v-for="item in selectedList" :key="item.namePath" class="autocomplete_list_item" @click="autocompleteClick(item)">
{{ item.namePath }}
</div>
</div>
</div>
</div>
// // 处理树结构图标
_processTree(treeData) {
if (treeData && treeData.length) {
for (let index = 0; index < treeData.length; index++) {
const item = treeData[index]
if (item.childrenButton && item.childrenButton.length > 0) {
item.expanded = false
treeData[index].childrenMenu = item.childrenButton
}
if (!this.allSelectedOptions.includes(item.menuId)) {
this.allSelectedOptions.push(item.menuId)
}
if (item.childrenMenu && item.childrenMenu.length > 0) {
this._processTree(item.childrenMenu)
} else {
delete item.childrenMenu
}
}
}
return treeData
},
selectAll(value) {
if (value) {
this.selectedOptions = [...this.allSelectedOptions]
} else {
this.selectedOptions = []
}
},
//点击
autocompleteClick(item) {
const nodeList = []
item.idPath && item.idPath.forEach((iItem, index) => {
console.log('🚀 ~ item.idPath&&item.idPath.forEach ~ iItem:', iItem)
nodeList.push(this.$refs.cascader.getNodeByValue(item.idPath.slice(0, index + 1)))
})
nodeList.forEach(item => {
this.$refs.cascader.handleExpand(item, true)
})
this.activePath = item.idPath
this.keyword = item.namePath
this.showselectedList = false
},
searchTree(node, target) {
if (!node) return []
const paths = []
const search = (node, path) => {
if (node.menuName.includes(target)) {
paths.push(path.slice()) // 使用slice()来复制路径
}
if (node.childrenMenu) {
for (let i = 0; i < node.childrenMenu.length; i++) {
path.push({
menuName: node.childrenMenu[i].menuName,
menuId: node.childrenMenu[i].menuId
})
search(node.childrenMenu[i], path)
path.pop() // 回溯,移除当前节点
}
}
}
search(node, []) // 初始路径为空数组
return paths
},
handleCascaderChange() {
if (this.selectedOptions.length === this.allSelectedOptions.length) {
this.selectCheckedAll = true
} else {
this.selectCheckedAll = false
}
},
handleInput(keyword) {
if (!keyword) {
this.showselectedList = false
return
}
const keywordList = [...this.searchTree({ menuName: '', childrenMenu: this.permissionTree }, keyword)]
const keywordListTemp = []
keywordList.forEach(item => {
const namePathList = []
const idPathList = []
item && item.forEach(tItem => {
namePathList.push(tItem.menuName)
idPathList.push(tItem.menuId)
})
keywordListTemp.push({
namePath: namePathList.join(' / '),
idPath: idPathList
})
})
this.selectedList = keywordListTemp
this.showselectedList = true
}
问题优化1:
- checkStrictly: false的时候,可以父类联动子类选中,但是绑定的值不是全部选中的值
- 需要使用 this.$refs.cascader.getCheckedNodes(false) 才能获取到所有的对应的值,才能实现全选的数量一致
问题优化2: checkStrictly: false的时候,后端需要获取半选的菜单id
// 定义一个函数,用于遍历树状结构数据,获取父类的id
findParents(treeData, childId, parents = []) {
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i]
if (node.menuId === childId) {
// 找到了目标子节点,返回其所有父节点id
return [...parents, node.menuId]
} else if (node.childrenMenu && node.childrenMenu.length > 0) {
// 递归遍历子节点的所有子节点
const result = this.findParents(node.childrenMenu, childId, [...parents, node.menuId])
if (result) {
// 找到了目标子节点,返回其所有父节点id
return result
}
}
}
// 没有找到目标子节点
return null
},
定义方法,根据当前全选的数组进行获取其父类的id,然后去重
let menuList = this.$refs.cascader.getCheckedNodes(false)
menuList = menuList.map(i => i.value)
// 半选的情况下,接口也需要传父类的id
const parentList = []
menuList.forEach(item => {
parentList.push(...this.findParents(this.permissionTree, item))
})