JavaScript几种形式的树结构菜单

下面为大家详细讲解 JavaScript 几种形式的树结构菜单的完整攻略。

下面为大家详细讲解 JavaScript 几种形式的树结构菜单的完整攻略。

什么是树结构菜单

树结构菜单是一种常见的用于网站导航或者分类展示的组件。树结构菜单的特点是可以展开、收起某一层级的菜单,同时高亮显示当前选中的菜单项。在前端开发中,我们可以使用 JavaScript 来实现这种树状结构的菜单。

JavaScript 实现树结构菜单的基本思路

在使用 JavaScript 实现树结构菜单的过程中,我们需要先获取到数据,然后根据数据生成对应的 HTML 元素,最后实现菜单的展开和收起效果。具体实现的流程如下:

1.定义数据结构: 利用JS对象来描述树形结构,例如:

let treeData = [
  {
    name: '菜单1',
    children: [
      { name: '菜单1.1', children: [] },
      { name: '菜单1.2', children: [] }
    ]
  },
  {
    name: '菜单2',
    children: [
      { name: '菜单2.1', children: [] },
      { name: '菜单2.2', children: [] }
    ]
  }
]

2.将树形结构转化为HTML结构,使用递归的方式遍历对象树,将对象属性渲染为HTML的列表项,如下所示:

function renderTree(data) {
  let ul = document.createElement('ul')
  data.forEach(item => {
    let li = document.createElement('li')
    li.innerHTML = item.name
    if(item.children && item.children.length) {
      li.appendChild(renderTree(item.children))
    }
    ul.appendChild(li)
  })
  return ul
}

3.绑定事件并实现菜单展开和收起效果,通过添加CSS类名来实现展开和收起菜单的效果,例如:

function initTree() {
  let root = document.querySelector('.tree')
  let tree = renderTree(treeData)
  root.appendChild(tree)
  // 绑定点击事件
  root.addEventListener('click', e => {
    let target = e.target
    if(target.tagName === 'LI' && target.children.length) {
      target.classList.toggle('open')
    }
  })
}

通过以上步骤,我们就可以实现一个基本的树状结构菜单。

JavaScript 实现树结构菜单的多种形式

除了基本的树状结构菜单,还可以实现以下两种形式:

1. 滑动展开效果

实现方法是:利用 CSS3 的 transition 属性给菜单添加滑动效果。

具体实现示例可以参考:https://codepen.io/eFishery/pen/VYJXGo

// JS 代码
let toggleEl = document.querySelectorAll('.tree-toggle');
let i;

for (i = 0; i < toggleEl.length; i++) {
    toggleEl[i].addEventListener('click', function(e) {
        e.preventDefault();

        let treeMenu = e.target.parentElement; //去掉最后一级的a标签
        let treeChild = treeMenu.childNodes[3];
        treeChild.classList.toggle('d-none');
        e.target.classList.toggle('fa-plus');
        e.target.classList.toggle('fa-minus');
    });
}
// CSS 代码
.tree-menu {
  list-style-type: none;
  margin: 0;
  padding: 0;
  padding-left: 20px;
}

.tree-menu li {
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tree-toggle {
  cursor: pointer;
  display: inline-block;
}

.d-none {
  display: none;
}

.fa-minus {
  display: none;
}

a > .fa-plus:before {
  content: "\\f067";
}

a > .fa-minus:before {
  content: "\\f068";
}

a:focus {
  outline: none;
}

.tree-menu li > .fa {
  position: absolute;
  left: -12px;
  top: 50%;
  margin-top: -10px;
}

.tree-menu > li > .fa {
  position: absolute;
  left: 0;
  top: 50%;
  margin-top: -10px;
}

.tree-menu li > ul {
  display: none;
}

.tree-menu li > ul.d-none {
  display: block;
}

.tree-menu li > ul {
  margin-top: 10px;
}

.tree-menu li > ul:before {
  content: '';
  display: block;
  border-left: 1px solid #ccc;
  bottom: 0;
  left: -20px;
  position: absolute;
  top: 0;
}

2. 搜索筛选效果

实现方法是:利用输入框输入关键词后,自动过滤不包含此关键词的菜单项。

具体实现示例可以参考:https://codepen.io/pokaworks/pen/BWYZzy

// JS 代码
// 输入框变化时执行
function onSearch(event) {
  // 搜索关键字
  // toLowerCase() 转换为小写,方便比较
  let keyword = event.target.value.trim().toLowerCase();

  // 从内存获取数据
  // 然后更新可见数据节点
  let searchRst = Search(keyword)
  if (searchRst) {
    $('#tree').empty();
    $('#tree').append(RenderVisible(searchRst));
    ExpandNode(event.target.value.trim());
  }
}

// 初始渲染visibleNodes
function RestoreNodes() {
  visibleNodes = [];
  visitedNodes = [];

  function Follow(node) {
    // 如果没访问过当前节点
    if (!visitedNodes[node.id]) {
      visitedNodes[node.id] = true;

      // 如果该节点包含我要的关键字
      if (node.title.toLowerCase().indexOf(this.keyword) > -1) {
        visibleNodes.push(node.id);
        ExpandParents(node.parentId);
      }

      // 深度优先遍历子节点
      node.children.forEach(Follow, this)
    }

  }

  this.keyword = '';
  treeData.forEach(Follow, this)
  return visibleNodes;
}

// 根据visibleNodes筛选节点
function RenderVisible(visibleNodes) {
  function Follow(node) {
    if (visibleNodes.indexOf(node.id) > -1) {
      results.push(node);
    }
  }

  var results = [];

  treeData.forEach(Follow);
  return SortNode(results);
}

// HTML 代码
<div class="form-group">
  <input type="text" 
         class="form-control" 
         placeholder="输入内容并回车搜索" 
         onblur="RestoreAll();"
         onkeyup="OnSearch(event);"/>
</div>

<div id="tree"></div>  

<script>
  $("#tree").append(RenderVisible(RestoreNodes()));
</script>

总结

通过以上的示例,我们可以看到,实现树状结构菜单的效果并不难,但其中涉及到的细节还是很多的,需要我们仔细斟酌。实际开发中,我们可以根据项目需要,选择不同的实现方式,以达到最佳效果。

本文标题为:JavaScript几种形式的树结构菜单

基础教程推荐