【问题标题】:Generate navigation from a multi-dimensional array从多维数组生成导航
【发布时间】:2010-05-20 20:47:26
【问题描述】:

问题:如何从多维数组生成导航,允许将不同的类应用于不同的子项?

在我需要多级导航之前,我是这样做的:

Home 
Pics 
About

并且是通过调用 nav() 生成的:

function nav(){       
    $links = array(
        "Home" => "home.php",
        "Pics" => "pics.php",
        "About" => "about.php"
    );

    $base = basename($_SERVER['PHP_SELF']);

    foreach($nav as $k => $v){
        echo buildLinks($k, $v, $base);
    }
}

这里是 buildLinks():

function buildLinks($name, $page, $selected){
    if($selected == $page){
       $theLink = "<li class=\"selected\"><a href=\"$page\">$name</a></li>\n";
    } else {
       $thelink = "<li><a href=\"$page\">$name</a></li>\n";
    }

    return $thelink;
}

我的问题,再次:

我将如何实现以下导航(并注意可见的子导航元素仅在该特定页面上出现):

Home
    something1
    something2 
Pics 
About

还有……

Home
Pics
    people
    places 
About

我的尝试

从外观上看,SPL 中的某些迭代器似乎很适合这个,但我不知道如何处理这个问题。我玩过 RecursiveIteratorIterator 但我不确定如何仅对子菜单项应用不同的样式,以及如何仅在正确的页面上显示这些项。

我构建了这个数组来测试,但不知道如何单独处理 submenu1 项:

$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
    "something1"=>"something1.php",
    "something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);

以下内容将按顺序打印出批次,但我该如何申请,对子菜单 1 项目说类名或仅在该人在“主页”页面时显示它们?

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($nav));

foreach($iterator as $key=>$value) {
    echo $key.' -- '.$value.'<br />';
}

这让我明白了:

Home
something1
something2
Pics
About

但我无法将类应用于这些子项,也无法仅有条件地显示它们,因为我不知道如何仅针对这些元素。

【问题讨论】:

    标签: php iterator navigation


    【解决方案1】:

    不要重新发明轮子,使用Zend_Navigation,你会很开心。

    【讨论】:

    • 在整个框架范围之外使用它似乎并不容易。无论如何,比使用邮件或日志等其他组件更棘手。
    • 现在我已经深入研究了它,如果不使用该框架的所有 MVC 组件,似乎不可能将 Zend_Navigation 集成到站点中。如果我错了,请纠正我。
    • 如果您不必使用 zend 模型和控制器。您甚至不必使用视图,但在这种情况下,您需要做一些技巧来轻松使用 Zend_View_Helper_Navigation,这是 Zend_Navigation 的重要组成部分。
    【解决方案2】:

    您在 RecursiveIteratorIterator 上走在了正确的轨道上。它本质上是一个递归迭代器。这是正确的方法:

    $nav = array(
        array(
        "Home" => "home.php",
        "submenu1" => array(
            "something1"=>"something1.php",
            "something2" => "something2.php")
        ),
        array("Pics" => "pics.php"),
        array("About" => "about.php"),
    );
    
    $it = new RecursiveIteratorIterator(
        new RecursiveArrayIterator($nav),
        RecursiveIteratorIterator::SELF_FIRST
    );
    
    foreach ($it as $k => $v) {
        if ($it->getDepth() == 0)
            continue;
        echo str_repeat("    ", $it->getDepth() - 1) .
            "$k => $v\n";
    }
    

    给予

    Home => home.php
    submenu1 => Array
        something1 => something1.php
        something2 => something2.php
    Pics => pics.php
    About => about.php
    

    【讨论】:

      【解决方案3】:

      看来您可能希望以更加面向对象的方式执行此操作。 如果没有,您似乎至少应该定义一个有意义的算法,现在您只是在盲目猜测。相反,定义。

      例如:

      我将我的导航定义为基于 php 哈希的树。导航项将具有以下内容:

      A) 如果存在顶级链接,则数组哈希将包含一个标记为“导航叶”的项目(子数组)

      b) 导航叶子将包含标记为“显示值”、“链接值”和“替代值”的元素。这些项目将用于生成锚标记。

      c) 如果一个元素有一个子菜单,除了包含一个“导航叶”之外,还会出现一个“子导航”元素。如果子导航元素具有可显示的导航项,则子导航元素将具有“导航叶”。

      然后您可以编写将根据您选择的定义显示您的导航的函数/方法。

      【讨论】:

        【解决方案4】:

        我会做的事情是这样的:

        class MenuItem {
            protected $active = false;
            protected $children = array();
            protected $name = '';
            protected $link = '';
        
            public function __construct($name, $link, $active) {}
        
            public function __toString() {
                //render this item
                $out = ''; #render here
                if (!$this->isActive()) { 
                    return $out;
                }
                $out .= '<ul>';
                foreach ($this->children as $child) {
                    $out .= (string) $child;
                }
                $out .= '</ul>';
                return $out;
            }
        
            public function isActive() {
                if ($this->active) {
                    return true;
                }
                foreach ($this->children as $child) {
                    if ($child->isActive()) {
                        return true;
                    }
                }
                return false;
            }
         }
        

        然后,您所拥有的只是一个数组中的根菜单项的集合...要构建您的菜单,您只需:

        $rootItems = array($item1, $item2);
        $out = '<ul>';
        foreach ($rootItems as $item) {
            $out .= (string) $item;
        }
        $out .= '</ul>';
        

        我将把构建对象、添加子对象等的语义留给用户...

        【讨论】:

          【解决方案5】:

          接下来如何重写nav函数:

          function nav($links, $level){       
              foreach($links as $k => $v) {
                  if (is_array($v)) {
                      nav($v, $level + 1)
                  } else {
                      echo buildLinks($k, $v, $base);
                  }
              }
          }
          

          比这样称呼它:

          $links = array(
          array(
          "Home" => "home.php",
          "submenu1" => array(
              "something1"=>"something1.php",
              "something2" => "something2.php")
          ),
          array("Pics" => "pics.php"),
          array("About" => "about.php")
          );
          nav($links, 0);
          

          【讨论】:

            【解决方案6】:

            恕我直言,最简单的方法就是进行递归调用,并使用导航的树结构描述(即嵌套数组)。未经测试的示例代码:

            <?php
            $links = array(
                "Home" => array("home.php", array(
                    "something1"=> array("something1.php", array()),
                    "hello"=> array("hello.php", array(
                        "world" => array("world.php", array()),
                        "bar" => array("bar.php", array()),
                    )),
                )),
                "Pics" => array("pics.php", array(
                    "people"=>"people.php",
                    "places" => "places.php",
                )),
                "About" => array("about.php", array()), // example no subitems
            );
            
            // use the following $path variable to indicate the current navigational position
            $path = array(); // expand nothing
            $path = array('Home'); // expand Home
            $path = array('Home', 'hello'); // also expand hello in Home
            
            // map indent levels to classes
            $classes = array(
                'item',
                'subitem',
                'subsubitem',
            );
            
            
            // recursive function to build navigation list
            function buildNav($links, $path, $classes)
            {
                // selected page at current level
                // NOTE: array_shift returns NULL if $path is empty.
                // it also alters the array itself
                $selected = array_shift($path);
                $class = array_shift($classes);
            
                echo "<ul>\n";
            
                foreach($links as $name => $link)
                {
                    list($href, $sublinks) = $link;
                    if ($name == $selected)
                    {
                        echo "<li class=\"selected $class\"><a href=\"$href\">$name</a>\n";
                        // recursively show subitems
                        // NOTE: path starts now with the selected subitem
                        buildNav($sublinks, $path, $classes);
                        echo "</li>\n";
                    }
                    else
                    {
                        echo "<li><a href=\"$href\" class=\"$class\">$name</a></li>\n";
                    }
                }
            
                echo "<ul>\n";
            }
            
            // actually build the navigation
            buildNav($links, $path, $classes);
            ?>
            

            【讨论】:

              【解决方案7】:

              @catchmeifyoutry

              谢谢你,你救了我的命 LoL。

              我稍微改变了你的功能以适应我的使用,结果出来了:

              $html['navi'] = array(
                  "Home"          => "/home/",
                  "DJs & Shows"   => "/djs-shows/",
                  "Playlists"     => "/playlists/",
                  "Newsbeat"      => "/newsbeat/",
                  "Reviews"       => "/reviews/",
                  "TV"            => "/tv/",
                  "Contact"       => "/contact/",
                  "Test"          => array("/test/",
                      array("Submenu 1" => "/test/link1",
                          "Submenu 2" => "/test/link2",
                          "Submenu 3" => "/test/link3",
                          "Submenu 4" => "/test/link4",
                          "Submenu 5" => "/test/link5",
                          "Submenu 6" => "/test/link6"
                      )
                  )
              );
              
              $classes = array(
                  'first-level',
                  'second-level',
                  'third-level',
              );
              
              function siteNavi($links, $classes) {
                  // The best way for MultiArray navigation (LOVE IT!)
                  // Array Shift selects first element and removes it from array
                  $class = array_shift($classes);
              
                  echo "<ul class=\"$class\">\n";
              
                  foreach($links as $name => $link) {
              
                      if (is_array($link) AND $class != "") {
              
                          list($link, $sublinks) = $link;
                          if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
              
                          echo "<li{$selected}><a href=\"{$link}\">{$name}</a>\n";
                          // recursively show subitems
                          // NOTE: path starts now with the selected subitem
                          siteNavi($sublinks, $classes);
                          echo "</li>\n";
              
                      } else {
              
                          if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
              
                          echo "<li{$selected}><a href=\"{$link}\" >{$name}</a></li>\n";
                      }
                  }
              
                  echo "</ul>\n";
              }
              

              非常感谢!

              我想知道这种代码对页面速度有多大影响。几微秒的毫秒:D

              【讨论】:

                猜你喜欢
                • 2015-03-31
                • 1970-01-01
                • 2018-07-12
                • 2022-01-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-07-28
                • 2012-07-29
                相关资源
                最近更新 更多