当前位置:首页 > React

react实现tree check

2026-01-27 08:48:02React

React 实现 Tree Check 功能

在 React 中实现树形结构的复选框(Tree Check)功能通常涉及递归渲染节点、管理选中状态以及处理父子节点的联动逻辑。以下是具体实现方法:

数据结构设计

树形结构的数据通常以嵌套对象形式表示,每个节点包含 idlabelchildren 等属性。例如:

const treeData = [
  {
    id: '1',
    label: 'Parent 1',
    children: [
      { id: '1-1', label: 'Child 1-1' },
      { id: '1-2', label: 'Child 1-2' },
    ],
  },
];

状态管理

使用 React 的 useStateuseReducer 管理选中状态。可以存储选中节点的 id 或完整路径:

react实现tree check

const [checkedKeys, setCheckedKeys] = useState(new Set());

递归渲染树节点

通过递归组件渲染树形结构,并为每个节点添加复选框:

const TreeNode = ({ node, checkedKeys, onCheck }) => {
  const isChecked = checkedKeys.has(node.id);

  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={isChecked}
          onChange={() => onCheck(node.id, !isChecked)}
        />
        {node.label}
      </label>
      {node.children && (
        <div style={{ marginLeft: '20px' }}>
          {node.children.map(child => (
            <TreeNode
              key={child.id}
              node={child}
              checkedKeys={checkedKeys}
              onCheck={onCheck}
            />
          ))}
        </div>
      )}
    </div>
  );
};

处理选中逻辑

实现父子节点联动的核心逻辑:

react实现tree check

  1. 选中父节点时自动选中所有子节点
  2. 取消父节点时自动取消所有子节点
  3. 部分选中子节点时父节点显示为半选状态
const updateCheckedKeys = (id, isChecked) => {
  const newCheckedKeys = new Set(checkedKeys);

  // 递归处理子节点
  const toggleChildren = (node) => {
    if (node.id === id) isChecked ? newCheckedKeys.add(id) : newCheckedKeys.delete(id);
    if (node.children) node.children.forEach(toggleChildren);
  };

  // 查找目标节点并更新
  const traverseTree = (nodes) => {
    nodes.forEach(node => {
      if (node.id === id || newCheckedKeys.has(id)) {
        toggleChildren(node);
      }
      if (node.children) traverseTree(node.children);
    });
  };

  traverseTree(treeData);
  setCheckedKeys(newCheckedKeys);
};

半选状态实现

通过计算子节点的选中状态决定父节点是否显示半选:

const isIndeterminate = (node) => {
  if (!node.children) return false;
  const childChecked = node.children.some(child => checkedKeys.has(child.id));
  const allChecked = node.children.every(child => checkedKeys.has(child.id));
  return childChecked && !allChecked;
};

在复选框属性中添加 indeterminate

<input
  type="checkbox"
  checked={isChecked}
  indeterminate={isIndeterminate(node)}
  onChange={() => onCheck(node.id, !isChecked)}
/>

完整示例代码

import React, { useState } from 'react';

const TreeCheck = ({ data }) => {
  const [checkedKeys, setCheckedKeys] = useState(new Set());

  const updateCheckedKeys = (id, isChecked) => {
    const newCheckedKeys = new Set(checkedKeys);
    const toggleChildren = (node) => {
      if (node.id === id) isChecked ? newCheckedKeys.add(id) : newCheckedKeys.delete(id);
      if (node.children) node.children.forEach(toggleChildren);
    };
    const traverseTree = (nodes) => {
      nodes.forEach(node => {
        if (node.id === id || newCheckedKeys.has(id)) toggleChildren(node);
        if (node.children) traverseTree(node.children);
      });
    };
    traverseTree(data);
    setCheckedKeys(newCheckedKeys);
  };

  const isIndeterminate = (node) => {
    if (!node.children) return false;
    const childChecked = node.children.some(child => checkedKeys.has(child.id));
    const allChecked = node.children.every(child => checkedKeys.has(child.id));
    return childChecked && !allChecked;
  };

  const TreeNode = ({ node }) => {
    const isChecked = checkedKeys.has(node.id);
    return (
      <div>
        <label>
          <input
            type="checkbox"
            checked={isChecked}
            indeterminate={isIndeterminate(node)}
            onChange={() => updateCheckedKeys(node.id, !isChecked)}
          />
          {node.label}
        </label>
        {node.children && (
          <div style={{ marginLeft: '20px' }}>
            {node.children.map(child => (
              <TreeNode key={child.id} node={child} />
            ))}
          </div>
        )}
      </div>
    );
  };

  return <div>{data.map(node => <TreeNode key={node.id} node={node} />)}</div>;
};

第三方库推荐

若需快速实现复杂功能,可考虑以下库:

  • react-checkbox-tree:专为树形复选框设计的组件。
  • rc-tree:Ant Design 的底层树组件,支持复选框。
  • downshift:灵活的可定制组件,适用于树形选择。

以上方法可根据实际需求调整,例如优化性能(如避免递归渲染)或添加异步加载子节点功能。

标签: reacttree
分享给朋友:

相关文章

电脑如何安装react

电脑如何安装react

安装 Node.js 和 npm React 依赖于 Node.js 和 npm(Node Package Manager)。从 Node.js 官网下载并安装最新稳定版本,安装完成后会自动包含 np…

react如何开发组件

react如何开发组件

React 组件开发基础 React 组件分为函数组件和类组件两种形式。函数组件是现代 React 开发的主流方式,结合 Hooks 可以实现完整功能。 函数组件示例: function Gree…

如何下载react

如何下载react

下载 React 的方法 通过 npm 或 yarn 安装 React 可以通过包管理器 npm 或 yarn 安装。确保已安装 Node.js(包含 npm),然后在项目目录中运行以下命令:…

react如何encode

react如何encode

React 中编码的实现方式 在 React 中,编码通常涉及对 URL、HTML 实体或特殊字符的处理。以下是几种常见的编码方法: 使用 encodeURIComponent 进行 URL 编码…

react如何检测

react如何检测

检测 React 应用的方法 使用 PropTypes 进行类型检查 PropTypes 是 React 内置的类型检查工具,用于验证组件的 props 是否符合预期。在开发环境中,PropTypes…

react 如何遍历

react 如何遍历

遍历数组 在React中遍历数组通常使用map方法,它会返回一个新的数组。map是处理数组并渲染列表元素的首选方法。 const items = ['Apple', 'Banana', 'Cherr…