将嵌套集模型转换为<ul>但隐藏"已关闭"子树

Mār*_*ovs 9 html php arrays traversal nested-sets

基于将修改后的预订树遍历模型(嵌套集)转换为<ul>

其中一个答案给出了正确的代码来显示完整的树.我需要的是始终显示第一级(深度= 0)和兄弟姐妹+孩子的活动列表项.目标是当用户选择列表项时扩展树的可见部分,该列表项是更多列表项的父项.

所以,如果我有这个清单:

1. item
2. item
  2.1. item
  2.2. item
    2.2.1. item
    2.2.2. item
    2.2.3. item
  2.3. item
  2.4. item
    2.4.1. item
    2.4.2. item
3. item
4. item
  4.1. item
  4.2. item
    4.2.1. item
    4.2.2. item
5. item
Run Code Online (Sandbox Code Playgroud)

如果当前列表项为"2",则列表应如下所示:

1. item
2. item // this needs class .selected
  2.1. item
  2.2. item
  2.3. item
  2.4. item
3. item
4. item
5. item
Run Code Online (Sandbox Code Playgroud)

如果当前列表项是"2.2.",列表应如下所示:

1. item
2. item // this needs class .selected
  2.1. item
  2.2. item // this needs class .selected
    2.2.1. item
    2.2.2. item
    2.2.3. item
  2.3. item
  2.4. item
3. item
4. item
5. item
Run Code Online (Sandbox Code Playgroud)

下面是一个示例代码,可以很好地显示完整的树.我还添加了lft/rgt/current来解决我的问题.

<?php
function MyRenderTree ( $tree = array(array('name'=>'','depth'=>'', 'lft'=>'','rgt'=>'')) , $current=false){

   $current_depth = 0;
   $counter = 0;

   $result = '<ul>';

   foreach($tree as $node){
       $node_depth = $node['depth'];
       $node_name = $node['name'];
       $node_id = $node['category_id'];

       if($node_depth == $current_depth){
           if($counter > 0) $result .= '</li>';
       }
       elseif($node_depth > $current_depth){
           $result .= '<ul>';
           $current_depth = $current_depth + ($node_depth - $current_depth);
       }
       elseif($node_depth < $current_depth){
           $result .= str_repeat('</li></ul>',$current_depth - $node_depth).'</li>';
           $current_depth = $current_depth - ($current_depth - $node_depth);
       }
       $result .= '<li id="c'.$node_id.'"';
       $result .= $node_depth < 2 ?' class="open"':'';
       $result .= '><a href="#">'.$node_name.'</a>';
       ++$counter;
   }
   $result .= str_repeat('</li></ul>',$node_depth).'</li>';

   $result .= '</ul>';

   return $result;
}

// "$current" may contain category_id, lft, rgt for active list item
print MyRenderTree($categories,$current);
?>
Run Code Online (Sandbox Code Playgroud)

hak*_*kre 8

由于您已经设法对序列进行排序,为什么不按需输出?

由于某些叶子需要显示为闭合,因此迭代器应该能够跳过未选定节点的子节点.

这样做可以让我想到解决终止输出树的问题(输出=解析).如果序列中的最后一个有效节点的深度大于0,该怎么办?我为此附加了一个NULL终止符.因此,在循环结束之前,仍可以关闭开放水平.

此外,迭代器重载节点以提供它们的常用方法,例如与当前选定的元素进行比较.

MyRenderTree函数(演示/完整代码)

编辑:演示键盘有问题,这里是源代码:Gist将
嵌套集模型转换为隐藏的"封闭"子树

function MyRenderTree($tree = array(array('name'=>'','depth'=>'', 'lft'=>'','rgt'=>'')) , $current=false)
{
    $sequence = new SequenceTreeIterator($tree);

    echo '<ul>';
    $hasChildren = FALSE;
    foreach($sequence as $node)
    {
        if ($close = $sequence->getCloseLevels())
        {
            echo str_repeat('</ul></li>', $close);
            $hasChildren = FALSE;
        }
        if (!$node && $hasChildren)
        {
            echo '</li>', "\n";
        }
        if (!$node) break; # terminator

        $hasChildren = $node->hasChildren();
        $isSelected = $node->isSupersetOf($current);

        $classes = array();
        $isSelected && ($classes[] = 'selected') && $hasChildren && $classes[] = 'open';
        $node->isSame($current) && $classes[] = 'current';

        printf('<li class="%s">%s', implode(' ', $classes), $node['name']);

        if ($hasChildren)
            if ($isSelected)
                echo '<ul>';
            else
                $sequence->skipChildren()
            ;
        else
            echo '</li>'
        ;
    }
    echo '</ul>';
}
Run Code Online (Sandbox Code Playgroud)

这也可以在单个foreach和一些变量中解决,但是我认为对于重复使用,基于SPL迭代器的实现更好.