layui树形搜索:关键字搜索与节点过滤

layui树形搜索:关键字搜索与节点过滤

【免费下载链接】layui 一套遵循原生态开发模式的 Web UI 组件库,采用自身轻量级模块化规范,易上手,可以更简单快速地构建网页界面。 【免费下载链接】layui 项目地址: https://gitcode.com/GitHub_Trending/la/layui

还在为复杂的树形结构数据查找而烦恼?layui tree组件的高效搜索与过滤功能,让您轻松实现精准定位与智能筛选!

本文将深入解析layui tree组件的搜索过滤机制,通过丰富的代码示例、流程图和最佳实践,帮助您掌握树形数据的智能检索技巧。读完本文,您将能够:

  • ✅ 掌握layui tree搜索功能的核心原理
  • ✅ 实现关键字实时搜索与节点过滤
  • ✅ 自定义搜索算法满足特定业务需求
  • ✅ 优化搜索性能提升用户体验
  • ✅ 处理复杂树形结构的搜索场景

一、搜索功能核心原理

layui tree组件的搜索功能基于DOM操作和文本匹配实现,其核心流程如下:

mermaid

1.1 搜索实现机制

在tree.js源码中,搜索功能主要通过以下关键代码实现:

// 搜索事件处理
that.elem.find('.layui-tree-search').on('keyup', function(){
  var input = $(this);
  var val = input.val();
  var pack = input.nextAll();
  var arr = [];

  // 遍历所有节点文本
  pack.find('.'+ ELEM_TEXT).each(function(){
    var entry = $(this).parents('.'+ELEM_ENTRY);
    if($(this).html().indexOf(val) != -1){
      arr.push($(this).parent());
      // 标记匹配节点并展开父级
      var select = function(div){
        div.addClass('layui-tree-searchShow');
        if(div.parent('.'+ELEM_PACK)[0]){
          select(div.parent('.'+ELEM_PACK).parent('.'+ELEM_SET));
        };
      };
      select(entry.parent('.'+ELEM_SET));
    };
  });

  // 隐藏不匹配节点
  pack.find('.'+ELEM_ENTRY).each(function(){
    var parent = $(this).parent('.'+ELEM_SET);
    if(!parent.hasClass('layui-tree-searchShow')){
      parent.addClass(HIDE);
    };
  });
});

二、基础搜索功能实现

2.1 基本搜索配置

layui tree提供了内置的搜索回调函数onsearch,可以监听搜索事件:

<div class="layui-input-block">
  <input type="text" class="layui-input" placeholder="搜索节点..." id="treeSearch">
</div>
<div id="treeDemo"></div>

<script>
layui.use(['tree'], function(){
  var tree = layui.tree;
  
  var data = [{
    title: '技术部门',
    id: 1,
    children: [{
      title: '前端开发组',
      id: 2,
      children: [{title: 'JavaScript工程师', id: 3}, {title: 'Vue开发工程师', id: 4}]
    },{
      title: '后端开发组', 
      id: 5,
      children: [{title: 'Java工程师', id: 6}, {title: 'Python工程师', id: 7}]
    }]
  }];

  tree.render({
    elem: '#treeDemo',
    data: data,
    id: 'searchTree',
    onsearch: function(obj){
      console.log('搜索匹配节点:', obj.elem);
      // obj.elem 包含所有匹配的节点元素
    }
  });

  // 手动触发搜索
  $('#treeSearch').on('keyup', function(){
    var keyword = $(this).val();
    // 这里需要自定义搜索逻辑
  });
});
</script>

2.2 搜索功能对比表

搜索方式实现复杂度性能表现适用场景用户体验
前端实时搜索中(依赖数据量)中小型数据集即时响应
后端API搜索高(分页加载)大型数据集需要等待
混合搜索优化平衡中型数据集平衡体验

三、高级搜索与过滤技巧

3.1 多条件复合搜索

实现支持多个字段的复合搜索功能:

/**
 * 高级搜索函数
 * @param {string} keyword 搜索关键字
 * @param {array} treeData 树形数据
 * @param {array} searchFields 搜索字段数组 ['title', 'id', 'description']
 */
function advancedTreeSearch(keyword, treeData, searchFields) {
  var results = [];
  
  function searchNodes(nodes) {
    nodes.forEach(function(node) {
      // 检查当前节点是否匹配
      var isMatch = searchFields.some(function(field) {
        return node[field] && 
               String(node[field]).toLowerCase().includes(keyword.toLowerCase());
      });
      
      if (isMatch) {
        results.push(node);
      }
      
      // 递归搜索子节点
      if (node.children && node.children.length > 0) {
        searchNodes(node.children);
      }
    });
  }
  
  searchNodes(treeData);
  return results;
}

// 使用示例
var searchResults = advancedTreeSearch('工程师', data, ['title', 'description']);
console.log('搜索结果:', searchResults);

3.2 实时搜索与防抖优化

为了避免频繁搜索造成的性能问题,建议使用防抖技术:

// 防抖函数实现
function debounce(func, wait) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      func.apply(context, args);
    }, wait);
  };
}

// 搜索输入框防抖处理
var searchInput = document.getElementById('treeSearch');
var debouncedSearch = debounce(function(e) {
  var keyword = e.target.value;
  if (keyword.trim() !== '') {
    filterTreeNodes(keyword);
  } else {
    resetTreeView();
  }
}, 300);

searchInput.addEventListener('input', debouncedSearch);

// 节点过滤函数
function filterTreeNodes(keyword) {
  var treeInstance = layui.tree;
  var allNodes = $('#treeDemo').find('.layui-tree-set');
  var hasMatch = false;
  
  allNodes.each(function() {
    var nodeText = $(this).find('.layui-tree-txt').text();
    var isVisible = nodeText.toLowerCase().includes(keyword.toLowerCase());
    
    if (isVisible) {
      $(this).removeClass('layui-hide');
      // 展开所有父级节点
      expandParentNodes($(this));
      hasMatch = true;
    } else {
      $(this).addClass('layui-hide');
    }
  });
  
  // 显示无结果提示
  if (!hasMatch) {
    showNoResults();
  } else {
    hideNoResults();
  }
}

四、自定义搜索算法

4.1 模糊搜索实现

/**
 * 模糊搜索算法
 * 支持拼音首字母、简拼、全拼搜索
 */
function fuzzySearch(keyword, treeData) {
  var results = [];
  var keywordLower = keyword.toLowerCase();
  
  // 拼音转换映射(简化版)
  var pinyinMap = {
    'js': 'javascript', 'vue': 'vue', 'java': 'java', 'py': 'python'
  };
  
  function searchRecursive(nodes) {
    nodes.forEach(function(node) {
      var nodeTitle = node.title.toLowerCase();
      var match = false;
      
      // 直接匹配
      if (nodeTitle.includes(keywordLower)) {
        match = true;
      }
      // 拼音简拼匹配
      else if (pinyinMap[keywordLower] && 
               nodeTitle.includes(pinyinMap[keywordLower])) {
        match = true;
      }
      // 首字母匹配
      else if (keywordLower.length === 1) {
        var firstChar = nodeTitle.charAt(0);
        if (firstChar === keywordLower) {
          match = true;
        }
      }
      
      if (match) {
        results.push(node);
      }
      
      // 继续搜索子节点
      if (node.children) {
        searchRecursive(node.children);
      }
    });
  }
  
  searchRecursive(treeData);
  return results;
}

4.2 权重评分搜索

对于更复杂的搜索需求,可以实现权重评分系统:

/**
 * 权重评分搜索算法
 */
function weightedSearch(keyword, treeData) {
  var scoredResults = [];
  
  function calculateScore(node, keyword) {
    var score = 0;
    var nodeTitle = node.title.toLowerCase();
    var keywordLower = keyword.toLowerCase();
    
    // 完全匹配得分最高
    if (nodeTitle === keywordLower) {
      score += 100;
    }
    // 开头匹配
    else if (nodeTitle.startsWith(keywordLower)) {
      score += 80;
    }
    // 包含匹配
    else if (nodeTitle.includes(keywordLower)) {
      score += 60;
    }
    // 拼音匹配
    else if (checkPinyinMatch(nodeTitle, keywordLower)) {
      score += 40;
    }
    
    // 根据节点层级调整权重(越靠近根节点权重越高)
    var levelWeight = 10 - getNodeLevel(node, treeData);
    score += Math.max(levelWeight, 1);
    
    return score;
  }
  
  function searchNodes(nodes) {
    nodes.forEach(function(node) {
      var score = calculateScore(node, keyword);
      if (score > 0) {
        scoredResults.push({
          node: node,
          score: score
        });
      }
      
      if (node.children) {
        searchNodes(node.children);
      }
    });
  }
  
  searchNodes(treeData);
  
  // 按分数排序
  return scoredResults.sort(function(a, b) {
    return b.score - a.score;
  });
}

五、性能优化策略

5.1 虚拟滚动优化

对于超大型树形结构,建议实现虚拟滚动:

// 虚拟滚动实现思路
function implementVirtualScroll(treeContainer, visibleCount) {
  var scrollTop = treeContainer.scrollTop;
  var containerHeight = treeContainer.clientHeight;
  var itemHeight = 40; // 假设每个节点高度40px
  
  var startIndex = Math.floor(scrollTop / itemHeight);
  var endIndex = startIndex + Math.ceil(containerHeight / itemHeight) + visibleCount;
  
  // 只渲染可见区域的节点
  renderVisibleNodes(startIndex, endIndex);
}

// 节点数据分页加载
function loadTreeDataPaginated(page, pageSize) {
  // 模拟分页数据加载
  var start = (page - 1) * pageSize;
  var end = start + pageSize;
  var pageData = allTreeData.slice(start, end);
  
  return {
    data: pageData,
    total: allTreeData.length,
    page: page,
    pageSize: pageSize
  };
}

5.2 搜索索引构建

预先构建搜索索引可以大幅提升搜索性能:

// 构建搜索索引
function buildSearchIndex(treeData) {
  var index = {};
  
  function indexNodes(nodes, path) {
    nodes.forEach(function(node) {
      var nodePath = path.concat([node.id]);
      
      // 索引节点标题
      var titleWords = node.title.toLowerCase().split(/\s+/);
      titleWords.forEach(function(word) {
        if (!index[word]) index[word] = [];
        index[word].push({
          node: node,
          path: nodePath
        });
      });
      
      // 递归索引子节点
      if (node.children) {
        indexNodes(node.children, nodePath);
      }
    });
  }
  
  indexNodes(treeData, []);
  return index;
}

// 使用索引快速搜索
function searchWithIndex(keyword, searchIndex) {
  var keywords = keyword.toLowerCase().split(/\s+/);
  var results = new Set();
  
  keywords.forEach(function(kw) {
    if (searchIndex[kw]) {
      searchIndex[kw].forEach(function(item) {
        results.add(item.node);
      });
    }
  });
  
  return Array.from(results);
}

六、实战案例:组织架构搜索系统

6.1 完整实现示例

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>组织架构搜索系统</title>
  <link rel="stylesheet" href="layui.css">
  <style>
    .search-container { margin: 20px; }
    .tree-container { height: 500px; overflow: auto; }
    .search-stats { margin-top: 10px; color: #666; }
    .highlight { background-color: #ff0; font-weight: bold; }
  </style>
</head>
<body>

<div class="search-container">
  <div class="layui-form">
    <div class="layui-form-item">
      <label class="layui-form-label">搜索组织</label>
      <div class="layui-input-inline">
        <input type="text" class="layui-input" id="orgSearch" 
               placeholder="输入部门/人员名称">
      </div>
      <div class="layui-form-mid layui-word-aux">
        支持拼音简拼、关键字搜索
      </div>
    </div>
  </div>
  
  <div class="search-stats" id="searchStats"></div>
</div>

<div class="tree-container">
  <div id="orgTree"></div>
</div>

<script src="layui.js"></script>
<script>
layui.use(['tree', 'util'], function(){
  var tree = layui.tree;
  var util = layui.util;
  
  // 组织架构数据
  var orgData = [{
    title: '集团公司',
    id: 'company',
    children: [{
      title: '技术研发中心',
      id: 'tech',
      children: [{
        title: '前端开发部',
        id: 'frontend',
        children: [
          {title: 'Web前端组', id: 'web', children: [
            {title: '张三 - Web工程师', id: 'zhangsan'},
            {title: '李四 - React开发', id: 'lisi'}
          ]},
          {title: '移动端组', id: 'mobile', children: [
            {title: '王五 - iOS开发', id: 'wangwu'},
            {title: '赵六 - Android开发', id: 'zhaoliu'}
          ]}
        ]
      },{
        title: '后端开发部',
        id: 'backend',
        children: [
          {title: 'Java开发组', id: 'java', children: [
            {title: '钱七 - Java工程师', id: 'qianqi'},
            {title: '孙八 - 架构师', id: 'sunba'}
          ]},
          {title: 'Python开发组', id: 'python', children: [
            {title: '周九 - Python开发', id: 'zhoujiu'},
            {title: '吴十 - 数据分析', id: 'wushi'}
          ]}
        ]
      }]
    },{
      title: '市场营销中心',
      id: 'market',
      children: [{
        title: '数字营销部',
        id: 'digital',
        children: [
          {title: '郑十一 - 营销经理', id: 'zheng11'},
          {title: '王十二 - 内容策划', id: 'wang12'}
        ]
      }]
    }]
  }];

  // 渲染组织树
  var treeInstance = tree.render({
    elem: '#orgTree',
    data: orgData,
    id: 'orgTreeInstance',
    showCheckbox: false,
    accordion: true
  });

  // 搜索功能实现
  var searchIndex = buildSearchIndex(orgData);
  var debouncedSearch = util.debounce(function(e) {
    var keyword = e.target.value.trim();
    var statsElement = document.getElementById('searchStats');
    
    if (keyword === '') {
      resetTreeView();
      statsElement.innerHTML = '';
      return;
    }
    
    var results = searchWithIndex(keyword, searchIndex);
    highlightSearchResults(results, keyword);
    
    // 显示搜索统计
    statsElement.innerHTML = `找到 ${results.length} 个匹配结果`;
    
  }, 300);

  document.getElementById('orgSearch').addEventListener('input', debouncedSearch);

  // 构建搜索索引
  function buildSearchIndex(treeData) {
    var index = {};
    
    function indexNode(node) {
      // 索引标题
      var title = node.title.toLowerCase();
      var words = title.split(/[\/\s\-]+/);
      
      words.forEach(function(word) {
        if (word.length < 2) return;
        if (!index[word]) index[word] = [];
        if (!index[word].includes(node)) {
          index[word].push(node);
        }
      });
      
      // 递归索引子节点
      if (node.children) {
        node.children.forEach(indexNode);
      }
    }
    
    treeData.forEach(indexNode);
    return index;
  }

  // 使用索引搜索
  function searchWithIndex(keyword, index) {
    var keywords = keyword.toLowerCase().split(/\s+/);
    var results = new Set();
    
    keywords.forEach(function(kw) {
      if (index[kw]) {
        index[kw].forEach(function(node) {
          results.add(node);
        });
      }
    });
    
    return Array.from(results);
  }

  // 高亮显示搜索结果
  function highlightSearchResults(results, keyword) {
    // 先重置所有节点
    resetTreeView();
    
    // 显示匹配节点并高亮
    results.forEach(function(node) {
      var nodeElement = findNodeElement(node.id);
      if (nodeElement) {
        nodeElement.removeClass('layui-hide');
        // 高亮匹配文本
        var textElement = nodeElement.find('.layui-tree-txt');
        var originalHtml = textElement.html();
        var highlighted = originalHtml.replace(
          new RegExp(keyword, 'gi'),
          '<span class="highlight">$&</span>'
        );
        textElement.html(highlighted);
        
        // 展开父级节点
        expandParentNodes(nodeElement);
      }
    });
  }

  // 查找节点DOM元素
  function findNodeElement(nodeId) {
    return $('#orgTree').find('.layui-tree-set[data-id="' + nodeId + '"]');
  }

  // 展开父级节点链
  function expandParentNodes(nodeElement) {
    var parentPack = nodeElement.parent('.layui-tree-pack');
    while (parentPack.length) {
      var parentNode = parentPack.parent('.layui-tree-set');
      parentNode.addClass('layui-tree-spread');
      parentPack = parentNode.parent('.layui-tree-pack');
    }
  }

  // 重置树形视图
  function resetTreeView() {
    $('#orgTree').find('.layui-tree-set').each(function() {
      $(this).removeClass('layui-hide');
      // 移除高亮
      var textElement = $(this).find('.layui-tree-txt');
      textElement.html(textElement.text());
    });
  }
});
</script>
</body>
</html>

6.2 性能测试数据

下表展示了不同数据量下的搜索性能对比:

节点数量初始渲染时间搜索响应时间内存占用推荐方案
100-500< 100ms< 50ms< 10MB前端实时搜索
500-2000100-500ms50-200ms10-50MB前端搜索+防抖
2000-10000500ms-2s200ms-1s50-200MB虚拟滚动+分页
10000+> 2s> 1s> 200MB后端搜索API

七、最佳实践总结

7.1 搜索功能设计要点

  1. 用户体验优先:实时反馈、智能提示、清晰的搜索结果展示
  2. 性能优化:防抖处理、虚拟滚动、搜索索引预构建
  3. 功能完整性:支持多字段搜索、模糊匹配、拼音搜索
  4. 可扩展性:易于添加新的搜索算法和过滤条件

7.2 常见问题解决方案

问题现象可能原因解决方案
搜索卡顿数据量过大实现虚拟滚动、分页加载
内存占用高节点数据过多采用懒加载、数据分片
搜索不准确匹配算法简单实现权重评分、模糊匹配
父节点未展开搜索逻辑缺陷确保展开匹配节点的所有父级

7.3 未来优化方向

  1. AI智能搜索:集成自然语言处理,理解搜索意图
  2. 协同过滤:基于用户行为推荐相关节点
  3. 语义搜索:理解搜索词的同义词、近义词
  4. 离线搜索:支持本地索引和离线搜索功能

通过本文的详细讲解和实战示例,相信您已经掌握了layui tree组件搜索过滤功能的精髓。在实际项目中,根据具体需求选择合适的搜索策略,结合性能优化手段,定能打造出高效、友好的树形数据搜索体验。

立即尝试:将上述代码示例集成到您的项目中,体验layui tree强大的搜索功能!

下期预告:我们将深入探讨layui tree的拖拽排序、动态编辑等高级功能,敬请期待!

【免费下载链接】layui 一套遵循原生态开发模式的 Web UI 组件库,采用自身轻量级模块化规范,易上手,可以更简单快速地构建网页界面。 【免费下载链接】layui 项目地址: https://gitcode.com/GitHub_Trending/la/layui

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值