首页
/ jQuery-TreeGrid实战:解决层级数据展示的3个非典型方案

jQuery-TreeGrid实战:解决层级数据展示的3个非典型方案

2026-03-14 05:40:25作者:霍妲思

在前端开发中,处理层级数据展示时,传统表格往往无法直观呈现父子关系,而树形结构又缺乏表格的规整布局。jQuery-TreeGrid作为一款专注于层级数据展示的前端表格插件,通过将树形结构与表格布局结合,完美解决了父子关系数据处理的难题。本文将通过三个实战场景,带你掌握该插件的核心用法与进阶技巧。

实现动态数据加载时的节点实时刷新

当你通过AJAX动态加载子节点数据时,传统表格会出现节点状态丢失、布局错乱等问题。这种场景在异步加载大数据量层级数据时尤为常见。

树形表格的核心原理是通过数据属性建立节点间的父子关联,就像文件系统的目录层级一样,每个节点通过唯一标识确定位置。

Step 1/3:准备动态加载的HTML结构

<table id="dynamicTreeGrid">
  <tr data-tt-id="1" data-tt-parent-id="0">
    <td>一级节点</td>
    <td><button class="load-children">加载子节点</button></td>
  </tr>
</table>

// 适用于需要异步加载子节点的场景

Step 2/3:实现节点加载与刷新逻辑

$(function() {
  $('#dynamicTreeGrid').treegrid({
    initialState: 'collapsed'
  });
  
  $('.load-children').click(function() {
    const $tr = $(this).closest('tr');
    const nodeId = $tr.data('tt-id');
    
    // 模拟AJAX请求
    setTimeout(() => {
      const newRows = `
        <tr data-tt-id="${nodeId}-1" data-tt-parent-id="${nodeId}">
          <td>二级节点1</td>
          <td></td>
        </tr>
        <tr data-tt-id="${nodeId}-2" data-tt-parent-id="${nodeId}">
          <td>二级节点2</td>
          <td></td>
        </tr>
      `;
      
      $tr.after(newRows);
      $('#dynamicTreeGrid').treegrid('refresh');
      $('#dynamicTreeGrid').treegrid('expand', nodeId);
    }, 500);
  });
});

// 核心在于加载后调用refresh方法重建节点关系

Step 3/3:添加加载状态与错误处理

// 在点击事件中添加
$tr.find('.load-children').prop('disabled', true).text('加载中...');

// 在setTimeout回调末尾添加
$tr.find('.load-children').remove();

// 提升用户体验的必要处理

💡 避坑提示:动态添加节点后必须调用refresh方法,否则插件无法识别新节点的层级关系。同时要注意,新添加的节点HTML结构必须包含data-tt-id和data-tt-parent-id属性。

相关问题:如何实现节点加载失败的重试机制?动态加载时如何显示加载动画?如何限制节点的最大加载深度?

实现跨分页的节点勾选状态保持

当树形表格需要分页展示时,切换页码后勾选状态丢失是常见问题。特别是在需要批量操作跨页数据时,这个问题会严重影响用户体验。

状态保持的原理是通过本地存储记录勾选状态,就像浏览器保存表单数据一样,在分页切换时重新应用这些状态。

Step 1/3:初始化勾选状态存储

$(function() {
  const treeGrid = $('#pagedTreeGrid').treegrid({
    onCheck: function(node) {
      const checkedState = JSON.parse(localStorage.getItem('treeGridChecked') || '{}');
      checkedState[node.id] = true;
      localStorage.setItem('treeGridChecked', JSON.stringify(checkedState));
    },
    onUncheck: function(node) {
      const checkedState = JSON.parse(localStorage.getItem('treeGridChecked') || '{}');
      delete checkedState[node.id];
      localStorage.setItem('treeGridChecked', JSON.stringify(checkedState));
    }
  });
});

// 适用于需要跨分页保持状态的场景

Step 2/3:分页加载时恢复勾选状态

function loadPage(pageNum) {
  // 模拟AJAX加载分页数据
  $.get(`/api/data?page=${pageNum}`, function(data) {
    $('#pagedTreeGrid tbody').html(renderRows(data));
    
    // 恢复勾选状态
    const checkedState = JSON.parse(localStorage.getItem('treeGridChecked') || '{}');
    Object.keys(checkedState).forEach(nodeId => {
      const $node = $(`tr[data-tt-id="${nodeId}"]`);
      if ($node.length) {
        $node.find('input[type="checkbox"]').prop('checked', true);
      }
    });
    
    $('#pagedTreeGrid').treegrid('refresh');
  });
}

// 关键是在数据渲染后立即恢复状态

Step 3/3:实现全选与清除功能

$('#selectAll').click(function() {
  const isChecked = $(this).prop('checked');
  const checkedState = isChecked ? 
    JSON.parse(localStorage.getItem('treeGridChecked') || '{}') : {};
  
  $('#pagedTreeGrid tbody tr').each(function() {
    const nodeId = $(this).data('tt-id');
    if (isChecked) {
      checkedState[nodeId] = true;
      $(this).find('input[type="checkbox"]').prop('checked', true);
    } else {
      delete checkedState[nodeId];
      $(this).find('input[type="checkbox"]').prop('checked', false);
    }
  });
  
  localStorage.setItem('treeGridChecked', JSON.stringify(checkedState));
});

// 全选功能需要同时更新存储和UI

💡 避坑提示:使用localStorage存储状态时,需注意节点ID的唯一性。对于临时数据,建议使用sessionStorage避免持久化存储占用空间。

相关问题:如何实现父子节点的级联勾选?如何限制可勾选的节点数量?如何在刷新页面后恢复勾选状态?

实现树形表格的拖拽排序功能

当需要允许用户自定义调整节点顺序时,传统树形表格往往难以实现直观的拖拽排序功能,特别是在保持层级关系的同时进行排序。

拖拽排序的原理是通过监听拖拽事件,记录节点位置变化,然后更新数据属性中的排序字段,就像调整文件系统中文件的顺序一样。

Step 1/3:引入拖拽排序依赖

<script src="js/jquery.treegrid.js"></script>
<script src="js/jquery-ui.min.js"></script>

// 需额外引入jQuery UI库支持拖拽功能

Step 2/3:初始化拖拽排序功能

$(function() {
  $('#sortableTreeGrid').treegrid({
    dragAndDrop: true
  }).sortable({
    items: 'tr[data-tt-id]',
    axis: 'y',
    helper: function(e, tr) {
      const $originals = tr.children();
      const $helper = tr.clone();
      $helper.children().each(function(index) {
        $(this).width($originals.eq(index).width());
      });
      return $helper;
    },
    update: function(event, ui) {
      const $movedRow = ui.item;
      const newPosition = $movedRow.index();
      const nodeId = $movedRow.data('tt-id');
      
      // 发送排序更新请求
      $.post('/api/update-order', {
        nodeId: nodeId,
        newPosition: newPosition
      });
    }
  });
});

// 适用于需要自定义节点顺序的场景

Step 3/3:原生JS替代实现

// 不使用jQuery UI的原生实现
document.querySelectorAll('#sortableTreeGrid tr[data-tt-id]').forEach(row => {
  row.draggable = true;
  
  row.addEventListener('dragstart', e => {
    e.dataTransfer.setData('text/plain', row.dataset.ttId);
    row.classList.add('dragging');
  });
  
  row.addEventListener('dragend', e => {
    row.classList.remove('dragging');
  });
});

document.querySelector('#sortableTreeGrid tbody').addEventListener('dragover', e => {
  e.preventDefault();
  const afterElement = getDragAfterElement(e.clientY);
  const draggable = document.querySelector('.dragging');
  if (afterElement == null) {
    e.target.closest('tbody').appendChild(draggable);
  } else {
    e.target.closest('tbody').insertBefore(draggable, afterElement);
  }
});

function getDragAfterElement(y) {
  const draggableElements = [...document.querySelectorAll('#sortableTreeGrid tr:not(.dragging)')];
  
  return draggableElements.reduce((closest, child) => {
    const box = child.getBoundingClientRect();
    const offset = y - box.top - box.height / 2;
    if (offset < 0 && offset > closest.offset) {
      return { offset: offset, element: child };
    } else {
      return closest;
    }
  }, { offset: Number.NEGATIVE_INFINITY }).element;
}

// 原生实现更轻量但需处理更多边界情况

💡 避坑提示:拖拽排序时需注意保持节点的层级关系,建议限制只能在同一父节点下进行排序。同时要处理好拖拽过程中的视觉反馈,提升用户体验。

相关问题:如何限制只能在特定层级内拖拽?如何实现跨父节点的拖拽?如何在拖拽时显示禁止拖拽的提示?

通过以上三个实战场景,我们不仅掌握了jQuery-TreeGrid的核心功能,还学会了如何解决动态加载、状态保持和拖拽排序等实际问题。与其他树形表格插件相比,jQuery-TreeGrid的优势在于其轻量级设计和灵活的API,能够满足大多数层级数据展示的需求。无论是在后台管理系统还是数据可视化场景,这款插件都能帮助开发者快速实现专业的树形表格功能。

在实际项目中,建议根据数据量大小选择合适的加载策略:小数据量可一次性加载,大数据量则应采用分页或动态加载方案。同时,要注意性能优化,避免在大量节点渲染时出现页面卡顿。通过合理运用本文介绍的技巧,你可以充分发挥jQuery-TreeGrid的潜力,打造出既美观又实用的层级数据展示界面。

登录后查看全文
热门项目推荐
相关项目推荐