需求
如下图的一个带搜索功能的树形选择器,搜索的时候隐藏掉没有关联的节点,同时,如果子节点中有命中的,则不隐藏。
示例图,来自Antd思路
- 首先,这个树形选择器的层级并不能确定,这里考虑用一个方法递归调用来实现。
- 递归实现的思路应该从最后一个子节点思考,并且父节点在子节点命中了搜索词的时候也要显示。
代码实现
最后实现的代码就如下,觉得还是比较有趣的,也算是写了很久无聊的业务代码写点逻辑换个心情吧。
铺垫一下,data
的数据结构:
treeData: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
name: PropTypes.string,
subTrees: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
name: PropTypes.string,
iconClassName: PropTypes.string,
})
),
})
),
递归function代码如下:
renderTreeNodes = data => {
const { searchValue, isSearchFilter } = this.props;
const returnData = [];
for (const item of data) {
const { name } = item;
let title = this.highlightSearchValue(name, searchValue);
if (item.iconClassName) {
title = (
<span>
<i className={`${ICON_FONT} ${item.iconClassName}`} />
{title}
</span>
);
}
if (item.subTrees) {
const subTreeNodes = this.renderTreeNodes(item.subTrees);
if (
(isSearchFilter && subTreeNodes.length > 0) ||
(!isSearchFilter || name.indexOf(searchValue) > -1)
) {
// if on searchFilter mode, push the parent node when child nodes exist
returnData.push(
<TreeNode key={item.id} title={title}>
{subTreeNodes}
</TreeNode>
);
}
} else if (!isSearchFilter || name.indexOf(searchValue) > -1) {
// if on searchFilter mode, push the last child node only when the node is match the search value
// otherwise, push the node anyway
returnData.push(<TreeNode key={item.id} title={title} />);
}
}
return returnData;
};
文本怎么高亮?实现如下:
highlightSearchValue = (name, searchValue) => {
if (!searchValue) {
return <span>{name}</span>;
}
const index = name.indexOf(searchValue);
const beforeStr = name.substr(0, index);
const afterStr = name.substr(index + searchValue.length);
return index > -1 ? (
<span>
{beforeStr}
<span className={cx('highlight-search-value')}>{searchValue}</span>
{afterStr}
</span>
) : (
<span>{name}</span>
);
};
网友评论