You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React.js应用中将LDIF数据以文件夹树形结构展示

在React中实现LDAP LDIF树形结构展示

1. 先将LDIF数据转换为树形结构

LDIF是基于条目和属性的文本格式,首先需要把它解析成React可直接使用的层级化对象数组。

示例LDIF数据

dn: dc=example,dc=com
objectClass: top
objectClass: domain

dn: ou=users,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit

dn: cn=John Doe,ou=users,dc=example,dc=com
objectClass: top
objectClass: person
cn: John Doe
sn: Doe

解析与树形构建函数

// 解析LDIF文本为条目数组
function parseLDIF(ldifText) {
  const entries = [];
  let currentEntry = {};
  const lines = ldifText.split('\n').filter(line => line.trim() !== '');

  for (const line of lines) {
    if (line.startsWith('dn:')) {
      if (Object.keys(currentEntry).length > 0) {
        entries.push(currentEntry);
      }
      currentEntry = { dn: line.split(': ')[1].trim() };
    } else {
      const [key, value] = line.split(': ', 2);
      currentEntry[key.trim()] = value.trim();
    }
  }
  if (Object.keys(currentEntry).length > 0) {
    entries.push(currentEntry);
  }
  return entries;
}

// 将条目数组转换为树形结构
function buildTree(entries) {
  const nodeMap = new Map();
  const rootNodes = [];

  // 初始化所有节点
  entries.forEach(entry => {
    const node = {
      id: entry.dn,
      label: entry.cn || entry.ou || entry.dc.split(',').shift().split('=')[1],
      data: entry, // 保留原始LDIF条目数据
      children: []
    };
    nodeMap.set(entry.dn, node);
  });

  // 构建父子层级关系
  entries.forEach(entry => {
    const dnParts = entry.dn.split(',');
    if (dnParts.length > 1) {
      const parentDn = dnParts.slice(1).join(',');
      const parentNode = nodeMap.get(parentDn);
      if (parentNode) {
        parentNode.children.push(nodeMap.get(entry.dn));
      }
    } else {
      rootNodes.push(nodeMap.get(entry.dn));
    }
  });

  return rootNodes;
}

2. 实现React树形组件

通过递归组件渲染层级结构,同时管理展开/折叠和选中状态:

import { useState } from 'react';

function LDAPTree({ treeData }) {
  // 存储展开的节点ID集合
  const [expandedIds, setExpandedIds] = useState(new Set());
  // 存储选中的节点ID(单选)
  const [selectedId, setSelectedId] = useState(null);

  // 切换节点展开/折叠状态
  const toggleExpand = (id) => {
    setExpandedIds(prev => {
      const newSet = new Set(prev);
      newSet.has(id) ? newSet.delete(id) : newSet.add(id);
      return newSet;
    });
  };

  // 切换节点选中状态
  const handleSelect = (id) => {
    setSelectedId(prev => prev === id ? null : id);
  };

  // 递归渲染单个节点
  const renderTreeItem = (node) => {
    const hasChildren = node.children.length > 0;
    const isExpanded = expandedIds.has(node.id);
    const isSelected = selectedId === node.id;

    return (
      <div key={node.id} className="tree-item">
        <div 
          className={`tree-item-header ${isSelected ? 'selected' : ''}`}
          onClick={() => handleSelect(node.id)}
        >
          {/* 展开/折叠按钮 */}
          {hasChildren && (
            <button 
              className="expand-btn"
              onClick={(e) => {
                e.stopPropagation(); // 避免触发选中事件
                toggleExpand(node.id);
              }}
            >
              {isExpanded ? '▼' : '▶'}
            </button>
          )}
          <span>{node.label}</span>
        </div>
        {/* 渲染子节点(仅展开时显示) */}
        {hasChildren && isExpanded && (
          <div className="tree-children">
            {node.children.map(child => renderTreeItem(child))}
          </div>
        )}
      </div>
    );
  };

  return (
    <div className="ldap-tree">
      {treeData.map(rootNode => renderTreeItem(rootNode))}
    </div>
  );
}

// 组件使用示例
function App() {
  // 替换为你的LDIF数据
  const ldifText = `dn: dc=example,dc=com
objectClass: top
objectClass: domain

dn: ou=users,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit

dn: cn=John Doe,ou=users,dc=example,dc=com
objectClass: top
objectClass: person
cn: John Doe
sn: Doe`;

  const entries = parseLDIF(ldifText);
  const treeData = buildTree(entries);

  return (
    <div className="app">
      <h1>LDAP 树形目录</h1>
      <LDAPTree treeData={treeData} />
    </div>
  );
}

export default App;

3. 添加基础样式(可选)

为了让树形结构更直观,添加以下CSS:

.ldap-tree {
  padding: 1rem;
  font-family: Arial, sans-serif;
}

.tree-item {
  margin: 0.25rem 0;
}

.tree-item-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.5rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.tree-item-header:hover {
  background-color: #f0f9ff;
}

.tree-item-header.selected {
  background-color: #e0f2fe;
  font-weight: bold;
}

.expand-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  font-size: 0.8rem;
}

.tree-children {
  margin-left: 1.5rem;
}

可选扩展功能

  • 多选支持:将selectedId改为selectedIds集合,实现批量选中
  • 搜索过滤:添加搜索框,过滤树节点并自动展开匹配路径
  • 右键菜单:添加上下文菜单,支持查看完整LDIF条目、编辑等操作
  • 异步加载:如果LDIF数据量极大,改为按需加载子节点,优化性能

内容的提问来源于stack exchange,提问作者Lucky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:17:40