一般的树形组件,也许会带上例如编辑、删除等自定义功能。例如下图:
而Antd的Tree并不像elementUI的Tree直接提供render-content来自定义节点内容的功能。而是只能给title传入自定义的ReactNode来渲染每个节点的内容。
那么代码也许会变成这样:
<Tree
showLine
>
<TreeNode title={<div>
...节点名
<span>编辑</span>
<span>删除</span>
</div>} key="0-0">
<TreeNode title={<div>
...节点名
<span>编辑</span>
<span>删除</span>
</div>} key="0-0-0">
<TreeNode title={<div>
...节点名
<span>编辑</span>
<span>删除</span>
</div>} key="0-0-0-0" />
<TreeNode title="leaf" key="0-0-0-1" />
</TreeNode>
</TreeNode>
</Tree>
也许你会说,title部分可以抽离,封装成一个组件。没错,当抽离了title部分的代码为一个组件时,我想到了,能否将整个TreeNode替换成我自己的TreeNode,类似这样:
<Tree
showLine
>
<TreeN title="parent 1" key="0-0">
<TreeN title="parent 1-0" key="0-0-0">
<TreeN title='leaf' key="0-0-0-0" />
<TreeN title="leaf" key="0-0-0-1" />
</Tree>
</TreeN>
</Tree>
TreeN函数内部:
...//省略部分代码
const {
title,
...rest
} = props;
return (
<TreeNode
title={
<div className={treeNode}>
<span>{title}</span>
<span className={deleteBtn}>删除</span>
<span className={edit}>编辑</span>
</div>
}
{...rest}
/>
);
然而此时,控制台报了一个错:
Tree only accept TreeNode as children.
// Tree组件只接收TreeNode组件作为子组件
Antd的所有组件基本都是基于rc-xxx,Tree则是基于rc-tree。
先google一波,发现也有人有类似的情况,即使并未找到解决方案:
查看编译后的代码,有这么一个函数:
function warnOnlyTreeNode() {
if (onlyTreeNodeWarned) return;
onlyTreeNodeWarned = true;
(0, _warning.default)(false, 'Tree only accept TreeNode as children.');
}
那么rc-tree是如何做子组件类型校验的呢?组件只不过是一个函数,于是我查看了TreeNode.prototype发现,其构造函数中有这么一个属性:isTreeNode,值为1,这下就简单明了了,看看源码。
function isTreeNode(node) {
return node && node.type && node.type.isTreeNode;
}
function getNodeChildren(children) {
return (0, _toArray.default)(children).filter(isTreeNode);
}
rc-tree把子组件当中isTreeNode不为真的组件全部过滤掉了,所以我们直接加上这么个属性并赋值为1,就可以让rc-tree误以为这就是他要的TreeNode,简化的组件代码如下:
import React from 'react';
import { Tree } from 'antd';
import { treeNode, edit, deleteBtn } from './typeTree.less';
const { TreeNode: AntdTreeNode } = Tree;
export default function TreeNode(props) {
const {
title,
...rest
} = props;
return (
<AntdTreeNode
title={
<div className={treeNode}>
<span>{title}</span>
<span className={deleteBtn}>删除</span>
<span className={edit}>编辑</span>
</div>
}
{...rest}
/>
);
}
TreeNode.isTreeNode = 1;
至此,组件就正常渲染出来啦~
虽然这个封装感觉有点多余,不过献给那些与我有同样好奇心的人吧~