MPTT树到菜单

时间:2012-03-23 13:24:22

标签: php mysql html treeview mptt

我有对象$pages 通过

foreach ($pages as $p):
    echo str_repeat('&nbsp;', 2 * $p->lvl).$p->nav.'<br/>';
endforeach;

其结构如http://pastebin.com/CSGenz7y

我需要渲染导航菜单。使用以下代码:

    echo '<ul id="jMenu">';
    $idn = 1;
    foreach ($pages as $s):
      if($s->lvl > $idn)
      {
        for($i=$s->lvl-$idn; $i>=1; $i--) echo '<ul>';
      }
      elseif($s->lvl < $idn)
      {
        for($i=$idn-$s->lvl; $i>=1; $i--) echo '</ul>';
      }
      $idn = $s->lvl;
      echo '<li>'.$s->nav.'</li>';
    endforeach;
    for($i=$s->lvl; $i>=1; $i--) echo '</ul>';
    echo '</ul>';

我得到以下输出:http://pastebin.com/MDMM2FcD

但我需要所有的孩子才能进入父母李:http://pastebin.com/JteBPGqb

我花了半天时间没有任何想法?

2 个答案:

答案 0 :(得分:1)

您应该等待数组的下一个子项关闭li。试试这段代码:

echo '<ul id="jMenu">';
$idn = 1;
foreach ($pages as $s):

    echo '<li>'.$s->nav;

    if($s->lvl > $idn){
        for($i=$s->lvl-$idn; $i>=1; $i--) echo '<ul>';
    }
    elseif($s->lvl < $idn) {
        for($i=$idn-$s->lvl; $i>=1; $i--) echo '</li></ul></li>';
    }
    else {
        echo '</li>';
    }

    $idn = $s->lvl;


endforeach;
for($i=$s->lvl; $i>=1; $i--) echo '</ul></li>';
echo '</ul>';

答案 1 :(得分:0)

此实现应该允许更容易的自定义。

用法:

<?php $orderLevelList = new OrderedLevelList; ?>
<ul class="main-menu">
<?php echo $orderLevelList->render($pages) ?>
</ul>

代码:

<?php
/**
 * Menu generator - expects that outer UL already exists (to allow custom class for example)
 */
class OrderedLevelList
{
    /**
     * Renders list
     *
     * @param array $pages array
     * @return string
     */
    public function render($pages)
    {
        $result = '';
        $lastLevel = $this->_getIntialLevel();
        foreach ($pages as $page) {
            $pageLevel = $this->_getLevel($page);
            if ($pageLevel > $lastLevel) {
                $result .= $this->_openList($pageLevel);
            } elseif ($pageLevel < $lastLevel) {
                $levelDiff = $lastLevel - $pageLevel;
                for ($i = $levelDiff; $i >= 0; $i--) {
                    $result .= $this->_closeList($pageLevel);
                    $result .= $this->_closeItem();
                }
            } else {
                $result .= $this->_closeItem();
            }
            $result .= $this->_openItem($page);
            $result .= $this->_renderItem($page);
            $lastLevel = $pageLevel;
        }
        $result .= $this->_closeItem();
        return $result;
    }

    /**
     * Renders contents of the item (what's inside the item)
     *
     * @param mixed $page
     * @return string
     */
    protected function _renderItem($page)
    {
        return sprintf('<a href="%s">%s</a>', $page['url'], $page['name']);
    }

    /**
     * Accessor for the level attribute
     *
     * Can be overridden if you use objects instead of associative arrays
     *
     * @param mixed $page
     * @return int
     */
    protected function _getLevel($page)
    {
        return $page['level'];
    }

    /**
     * Opens new level of list
     *
     * Can be overridden if you want for example OLs
     *
     * @param int $currentLevel
     * @return string
     */
    protected function _openList($currentLevel)
    {
        return sprintf('<ul class="%s">', 'level-' . $currentLevel);
    }

    /**
     * Opens new item of list
     *
     * Override if you need more complex markup of items
     *
     * @param mixed $page
     * @return string
     */
    protected function _openItem($page)
    {
        return sprintf('<li class="%s">', 'item-' . $page['id']);
    }

    /**
     * Closes current level of the list
     *
     * @param int $currentLevel
     * @return string
     */
    protected function _closeList($currentLevel)
    {
        return '</ul>';
    }

    /**
     * Closes the previous item
     *
     * The actual item being closed cannot be accessed due to
     * the way the algorithm works
     *
     * @return string
     */
    protected function _closeItem()
    {
        return '</li>';
    }

    /**
     * @return int
     */
    protected function _getIntialLevel()
    {
        return 1;
    }
}