如何递归遍历ul并找出它中有多少ul

时间:2015-05-19 02:12:13

标签: javascript jquery html recursion frontend

我正在尝试在jquery中编写一个函数,它将遍历ul,其中包含嵌套的ul。我希望跟踪我有多少ul或“层”,并给一个ul的li子项提供一个类标签,对应于其父级ul所在的“层”。 html的结构是这样的`

<div class="region region--megamenu">
  <div class="block block--services-menu">
    <ul class="menu"> 
      <li class="first last expanded active-trail">  
        <a href="/services" class="active-trail">Services</a>
        <ul class="menu"> <!-- This ul can have any number of metacategory li's inside of it -->
          <li class="second layer of li">
            <a href="/metacategory-page">Metacategory Pages</a>
            <ul class="menu"> <!-- This ul can have any number of ul's inside of it -->
              <li>
                <a href="/service-page-url"></a>
              </li>
              <li>
                <a href="/service-page-url"></a>
              </li>
            </ul> 
          </li>
          <li>
            <a href="/metacategory-page">Metacategory Pages</a>
            <ul class="menu"> <!-- This ul can have any number of ul's inside of it -->
              <li>
                <a href="/service-page-url"></a>
              </li>
              <li>
                <a href="/service-page-url"></a>
              </li>
            </ul> 
          </li>      
        </ul>
      </li>
    </ul>
  </div>
</div>

每个li都会得到一个数字作为新的类标签。

因此,第一个li元素将获得标签<li class="1 first layer of li">,而第二个li元素将标记为<li class="2 second layer of li">

3 个答案:

答案 0 :(得分:2)

您可以使用 JQuery .find()方法轻松完成此操作。

<强> HTML

<div class="region region--megamenu">
  <div class="block block--services-menu">
    <ul class="menu"> 
      <li class="first last expanded active-trail">  
        <a href="/services" class="active-trail">Services</a>
        <ul class="menu"> <!-- This ul can have any number of metacategory li's inside of it -->
          <li class="second layer of li">
            <a href="/metacategory-page">Metacategory Pages</a>
            <ul class="menu"> <!-- This ul can have any number of ul's inside of it -->
              <li>
                <a href="/service-page-url"></a>
              </li>
              <li>
                <a href="/service-page-url"></a>
              </li>
            </ul> 
          </li>
          <li>
            <a href="/metacategory-page">Metacategory Pages</a>
            <ul class="menu"> <!-- This ul can have any number of ul's inside of it -->
              <li>
                <a href="/service-page-url"></a>
              </li>
              <li>
                <a href="/service-page-url"></a>
              </li>
            </ul> 
          </li>      
        </ul>
      </li>
    </ul>
  </div>
</div>

<div id="info"></div>

<强> JS / JQUERY

var allListElements = $( "ul" );
var ulsInUl = $( "ul.menu" ).find( allListElements ).length;
document.getElementById("info").innerHTML = "Uls in UL Class main: " + ulsInUl;


查看 JSFiddle http://jsfiddle.net/aaaprbst/1/

答案 1 :(得分:2)

在普通JS中,您可以使用递归函数(尽管线性函数会更快)。这会降低DOM并为每个LI添加一个类。当在LI上递归调用时,它会递增该调用的图层数。

不确定它是否符合您的目的,但可能足够接近。你也可以获得UL,然后为他们的直接LI子女添加一个特定于图层的类。

如果需要,可以优化下面的函数来跳过不会有LI子元素的非空元素(例如脚本元素)。

<style type="text/css">

.foo-0 {
 background-color: red;
}
.foo-1 {
 background-color: blue;
}
.foo-2 {
 background-color: green;
}

</style>

<div id="d0">
  <ul>
    <li>layer 1
    <li>layer 1
      <ul>
        <li>layer 2
        <li>layer 2
          <ul>
            <li>layer 3
            <li>layer 3
          </ul>
        <li>layer 2
      </ul>
    <li>layer 1
    <li>layer 1
  </ul>
</div>

<script>

/*
** @param {DOM element} root - element to start from, default is document.body
** @param {string} classPre  - prefix for class to add
** @param {number} layer     - current level, default is 0
*/
function addULLayerClass(root, classPre, layer) {
  root = root || document.body;
  layer = layer || 0;

  var node, nodes = root.childNodes;
  var tagName;

  for (var i=0, iLen=nodes.length; i<iLen; i++) {
    node = nodes[i];
    tagName = node.tagName && node.tagName.toLowerCase();

    // If this is an LI, add class with layer number
    // and call recursively
    if (tagName == 'li') {
      node.className = classPre + '-' + layer;
      addULLayerClass(node, classPre, layer + 1);

    // Otherwise, if it's an element that can have children,
    // call recursively          
    } else if (node.nodeType == 1) {
      addULLayerClass(node, classPre, layer);
    }
  }
}

addULLayerClass(document.getElementById('d0'), 'foo');

</script>

答案 2 :(得分:1)

这是我实现的代码,它完全符合我的要求。感谢大家的贡献。

  var parentUL = $( "ul.menu" );
  var startSearchForParentsHere = ".block--services-menu";
      $( startSearchForParentsHere ).find( parentUL ).each(function(){
          layersDeep = $(this).parentsUntil(startSearchForParentsHere, parentUL).length;
          $(this).children().addClass('accordion-layer' + ' ' + layersDeep);
      })

进一步的反馈和其他创意解决方案也非常感谢!