项目开发是用的vue+ant-design-vue
最近收到一个新的搜索需求,需要对目录树进行搜索,并将搜索到的值进行高亮与展开显示。
废话不多说直接上代码,以下代码只是一个简单的demo。
<template>
<div>
<a-input-search v-model="searchStr" placeholder="输入搜选项" style="width:200px;" @search="onSearch"></a-input-search>
<!-- selectedKeys是选中项key的集合,expandedKeys是展开项key的集合 -->
<a-tree
v-model="checkedKeys"
:treeData="treeData"
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeys"
@expand="onExpand"
:autoExpandParent="autoExpandParent"
:replaceFields="replaceFields"
@select="onSelect"
>
<template slot='title' slot-scope={name}>
<span v-html="name.replace(new RegExp(searchValue,'g'),'<span style=color:#f50>'+ searchValue +'</span>')"></span>
</template>
</a-tree>
</div>
</template>
<script>
const treeData = [
{
name: '0-0',
key: '0-0',
scopedSlots: {title: "title"},
children: [
{
name: '0-0-0',
key: '0-0-0',
scopedSlots: {title: "title"},
children: [
{ name: '0-0-0-0', key: '0-0-0-0',scopedSlots:{title: "title"},children:[
{ name: '0-0-0-0-0', key: '0-0-0-0-0',scopedSlots:{title: "title"}, children:[
{name: '0-0-0-0-0-0', key: '0-0-0-0-0-0',scopedSlots:{title: "title"}},
{name: '0-0-0-0-0-1', key: '0-0-0-0-0-1',scopedSlots:{title: "title"}}
]},
{ name: '0-0-0-0-1', key: '0-0-0-0-1',scopedSlots:{title: "title"},children:[
{ name: '0-0-0-0-1-0', key: '0-0-0-0-1-0',scopedSlots:{title: "title"}},
{ name: '0-0-0-0-1-1', key: '0-0-0-0-1-1',scopedSlots:{title: "title"}}
]},
{ name: '0-0-0-0-2', key: '0-0-0-0-2',scopedSlots:{title: "title"} },
] },
{ name: '0-0-0-1', key: '0-0-0-1',scopedSlots:{title: "title"} },
{ name: '0-0-0-2', key: '0-0-0-2',scopedSlots:{title: "title"} },
],
},
{
name: '0-0-1',
key: '0-0-1',
scopedSlots:{title: "title"},
children: [
{ name: '0-0-1-0', key: '0-0-1-0',scopedSlots:{title: "title"} },
{ name: '0-0-1-1', key: '0-0-1-1',scopedSlots:{title: "title"} },
{ name: '0-0-1-2', key: '0-0-1-2',scopedSlots:{title: "title"} },
],
},
{
name: '0-0-2',
key: '0-0-2',
scopedSlots: {title: "title"}
},
],
},
{
name: '0-1',
scopedSlots: {title: "title"},
key: '0-1',
children: [
{ name: '0-1-0-0', key: '0-1-0-0',scopedSlots: {title: "title"}},
{ name: '0-1-0-1', key: '0-1-0-1',scopedSlots: {title: "title"}},
{ name: '0-1-0-2', key: '0-1-0-2',scopedSlots: {title: "title"}},
],
},
{
name: '0-2',
key: '0-2',
scopedSlots: {title: "title"}
},
];
export default {
data() {
return {
replaceFields:{title:'name'},
expandedKeys: [],
backupsExpandedKeys: [],
autoExpandParent: false,
checkedKeys: [],
selectedKeys: [],
searchValue: '',
treeData,
searchStr: ''
};
},
methods: {
onSearch(){
var vm=this;
//添加这行代码是为了只点击搜索才触发
vm.searchValue = vm.searchStr;
//如果搜索值为空,则不展开任何项,expandedKeys置为空
//如果搜索值不位空,则expandedKeys的值要为搜索值的父亲及其所有祖先
if(vm.searchValue === ''){
vm.expandedKeys = [];
}else{
//首先将展开项与展开项副本置为空
vm.expandedKeys = [];
vm.backupsExpandedKeys = [];
//获取所有存在searchValue的节点
let candidateKeysList = vm.getkeyList(vm.searchValue,vm.treeData,[]);
//遍历满足条件的所有节点
candidateKeysList.map(
item=>{
//获取每个节点的母亲节点
var key=vm.getParentKey(item,vm.treeData);
//当item是最高一级,父key为undefined,将不放入到数组中
//如果母亲已存在于数组中,也不放入到数组中
if(key && !vm.backupsExpandedKeys.some(item=>item===key))
vm.backupsExpandedKeys.push(key);
}
)
let length=this.backupsExpandedKeys.length;
for(let i=0;i<length;i++){
vm.getAllParentKey(vm.backupsExpandedKeys[i],vm.treeData)
}
vm.expandedKeys = vm.backupsExpandedKeys.slice();
}
},
//获取节点中含有value的所有key集合
getkeyList(value,tree,keyList){
//遍历所有同一级的树
for(let i=0;i<tree.length;i++){
let node = tree[i];
//如果该节点存在value值则push
if(node.name.indexOf(value)>-1){
keyList.push(node.key);
}
//如果拥有孩子继续遍历
if(node.children){
this.getkeyList(value,node.children,keyList);
}
}
//因为是引用类型,所有每次递归操作的都是同一个数组
return keyList;
},
//该递归主要用于获取key的父亲节点的key值
getParentKey(key,tree){
let parentKey,temp;
//遍历同级节点
for(let i=0;i<tree.length;i++){
const node=tree[i];
if(node.children){
//如果该节点的孩子中存在该key值,则该节点就是我们要找的父亲节点
//如果不存在,继续遍历其子节点
if(node.children.some(item=>item.key===key)){
parentKey = node.key;
}else if(temp=this.getParentKey(key,node.children)){
//parentKey = this.getParentKey(key,node.children)
//改进,避免二次遍历
parentKey = temp;
}
}
}
return parentKey;
},
//获取该节点的所有祖先节点
getAllParentKey(key,tree){
var parentKey;
if(key){
//获得父亲节点
parentKey = this.getParentKey(key,tree);
if(parentKey){
//如果父亲节点存在,判断是否已经存在于展开列表里,不存在就进行push
if(!this.backupsExpandedKeys.some(item=>item===parentKey)){
this.backupsExpandedKeys.push(parentKey);
}
//继续向上查找祖先节点
this.getAllParentKey(parentKey,tree):
}
}
},
onExpand(expandedKeys) {
//用户点击展开时,取消自动展开效果
this.expandedKeys = expandedKeys;
this.autoExpandParent = false;
},
onCheck(checkedKeys) {
console.log('onCheck', checkedKeys);
this.checkedKeys = checkedKeys;
},
onSelect(selectedKeys, info) {
console.log('onSelect', info);
this.selectedKeys = selectedKeys;
},
},
};
</script>
<style scope>
</style>
效果图如下
就是类似于上面图的效果。
上图获取父亲节点和获得所有的祖先节点应该是可以优化的,如果有优化方案欢迎评论区讨论。
这只是基于ant-design-vue实现的,本人因为甲方对树的性能要求,被迫自己重新写了个类似于上述功能的树,