产品需求:
- 用户组织数据可一次获取全部,组织下的设备则在展开时异步获取
- 用户可设置自定义的显示层级,只展示对应层级的节点
- 优化树节点过滤方法,匹配的组织将展示下面的子组织,可继续向下展开操作
- 节点刷新
例:浙江省展开时会获取下面的设备,并与下属组织节点合并
根据节点类型调用不同的接口加载数据
/**
* 根据节点类型调用不同的接口加载数据
* @param node
* @param resolve
*/
getTreeData(node, resolve){
if(node.level === 0 && !node.label){
// 获取全部组织数据
getUserOrg().then(res => {
this.treeAreaData = res.data
this.treeData = this.onHideTreeLevel(this.treeAreaData)
}).finally(() => {
if(this.showCheckbox && this.defaultCheckedAll){
this.checkedAll()
}
this.$refs.tree.filter(this.filterText)
})
} else if(node.data.type === 'device'){
//获取设备下的通道
this.getDevicesChannels(node, resolve)
} else {
// 获取组织下的设备
this.getNodeDevices(node, resolve)
}
}
显示用户选择层级
/**
* 根据用户设置隐藏层级
*/
onHideTreeLevel(treeData, level = 0){
if(level < this.hideLevel){
let newTreeArr = []
treeData.forEach(item => {
if(item.children){
newTreeArr = newTreeArr.concat(this.onHideTreeLevel(item.children, level + 1))
}
})
return newTreeArr
} else {
return treeData
}
},
优化树节点过滤方法,匹配的组织将展示下面的子组织 踩坑1:懒加载的树,即使treeData是全的也不会渲染出node,需要主动通过数据进行过滤
/**
* 树过滤方法
* @param value
* @param data
* @param node
* @returns {boolean}
*/
filterNode(value, data, node) {
if (!value) return true;
if(this.filterType === '1'){
// 通道
if(data.type === 'channel'){
return data.organizeName.indexOf(value) !== -1;
} else {
return true
}
} else{
// 组织
if(data.type === 'channel' || data.type === 'device'){
return this.getParentMatching(value, data, node)
} else {
let parentLike = this.getParentMatching(value, data, node)
let childLike = false
if(data.children.length > 0 && node.childNodes.length === 0){
//懒加载已有数据匹配优化
childLike = this.getChildMatching(value, data)
}
return data.organizeName.indexOf(value) !== -1 || parentLike || childLike;
}
}
}
/**
* 父节点是否匹配
* @param value
* @param data
* @param node
* @returns {boolean}
*/
getParentMatching(value, data, node){
let parentLike = false
let parent = node.level > 1 ? node.parent : null
while(parent && !parentLike){
if(parent.data.organizeName.indexOf(value) !== -1){
parentLike = true
break
}
parent = parent.data.parentId ? parent.parent : null
}
return parentLike
}
/**
* 子数据匹配
* @param value
* @param data
* @returns {boolean}
*/
getChildMatching(value, data){
let childData = data.children
let matching = false
childData.forEach(item => {
if(item.type !== 'channel' || item.type !== 'device'){
if(item.organizeName.indexOf(value) !== -1){
matching = true
}
}
if(item.children && item.children.length > 0){
let matchingChild = this.getChildMatching(value, item)
if(matchingChild){
matching = true
}
}
})
return matching
}
参数传递优化,树节点子节点全选,只传父节点(例:地市节点全部选中则只传浙江省id)
/**
* 获取树已选择的id
* 父节点选中则不用传子节点
* 按此规则过滤数据
*/
getSelectedIds(){
let store = this.$refs.tree.store
const checkedNodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.childNodes : node.childNodes;
childNodes.forEach(child => {
if (child.checked) {
checkedNodes.push(child.data);
}
if (child.indeterminate) {
traverse(child);
}
});
};
traverse(store)
return checkedNodes;
}
节点刷新
/**
* 刷新节点
* @param data
* @param node
*/
handleNodeFresh(data, node){
node.loading = true
let oldExpanded = node.expanded // 记录当时展开状态
node.expanded = false
node.data.children = node.data.children.filter(item => {
return item.type !== 'device' && item.type !== 'channel'
})
// 记录当前选中数据
let checkedNodeKeys = this.$refs.tree.getCheckedKeys()
new Promise(resolve => {
this.getTreeData(node, resolve)
}).then(res => {
this.$refs.tree.updateKeyChildren(data.id, res)
node.expanded = oldExpanded // 还原展开状态
}).finally(() => {
if(this.showCheckbox){
//重新选中数据
this.$refs.tree.setCheckedKeys(checkedNodeKeys)
}
node.loading = false
})
},
小技巧: 1.可以通过$refs.tree.store获取整棵树的nodes根节点