react + ts 的 treeSelect 组件实现(2) | 青训营笔记

124 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 14 天,让正式我们开始 treeSelect 组建的编写。这篇文章首先先实现树形菜单的展开收起、选择相关的功能。

功能实现

展开收起树形结构

我们将使用一个Set来存储展开的节点,当点击展开/收起按钮时,我们将节点的value添加到Set中,如果已经存在,则删除。 这里使用react hooks的useState来实现。为的是在展开/收起节点时,重新渲染组件。

const [expanded, setExpanded] = useState(new Set());

然后再定义一个handleExpand函数,用来处理展开/收起节点的逻辑。

const handleExpand = (node: TreeNode<T>) => {
  const newExpanded = new Set(expanded);
  if (newExpanded.has(node.value)) {
    newExpanded.delete(node.value);
  } else {
    newExpanded.add(node.value);
  }
  setExpanded(newExpanded);
};

在上述代码中,我们使用了一个新的Set来存储展开的节点,这是因为我们不希望直接修改原来的Set,而是返回一个新的Set。这样可以避免在修改Set时,引起不必要的错误。

渲染部分,我们需要判断节点是否有子节点,如果有子节点,我们就渲染展开/收起按钮。并且要判断当前节点是否已经展开,如果已经展开,我们就渲染收起按钮,否则渲染展开按钮。

{expandable ? (
  node.children && node.children.length > 0 ? (
    expanded.has(node.value) ? (
      <IoMdArrowDropdown />
    ) : (
      <IoMdArrowDropright />
    )
  ) : (
    <IoMdArrowDropdown className="space" />
  )
) : null}

这里使用的图标是来自于react-icons库,用着简单方便。

选择节点

我们将使用一个数组来存储选中的节点,当点击选择框时,我们将节点添加到数组中,如果已经存在,则删除。同样是使用useState来实现。

const [selected, setSelected] = useState<TreeNode<T>[]>([]);

然后再定义一个handleSelect函数,用来处理选择节点的逻辑。

const handleSelect = (node: TreeNode<T>) => {
  const newSelected = [...selected];
  const index = newSelected.findIndex((item) => item.value === node.value);
  if (index >= 0) {
    newSelected.splice(index, 1);
  } else {
    newSelected.push(node);
  }
  setSelected(newSelected);
};

这里的逻辑和展开/收起节点的逻辑类似,在后续有更多的需求时,可以在这里进行扩展。

渲染部分,我们需要判断是否需要显示选择框,如果需要,我们就渲染选择框。并且要判断当前节点是否已经选中,如果已经选中,我们就渲染选中状态的选择框,否则渲染未选中状态的选择框。

{checkable ? (
  <div
    className={checkBoxClass}
    onClick={(e) => {
      e.stopPropagation();
      handleSelect(node);
    }}
    data-testid={`checkBoxContainer` + node.label}
  >
    <CheckBox
      displayIcon={checkable}
      icon={icon}
      isSelected={selected.includes(node)}
    />
  </div>
) : null}

这里使用的CheckBox组件是我之前写的一个组件,用来实现复选框的功能,这里就不贴出来了。