2010-05-20 2 views
7

Вопрос: Как создать навигацию, позволяющую применять разные классы к различным подпозициям, из многомерного массива?Сгенерировать навигацию из многомерного массива

Вот как я делал это прежде, чем я имел какой-либо необходимости для навигации многоуровневого:

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 

Но у меня нет никакой возможности применять классы этих подпунктов и никоим образом не только отображать их условно, потому что я не вижу, как предназначаться только эти элементы.

ответ

1

Вы были на правильном пути с помощью 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 
1

Кажется, что вы можете сделать это более объектно-ориентированным способом. Если нет, кажется, что вы должны хотя бы определить алгоритм, который имеет смысл, прямо сейчас вы просто слепо угадываете. Вместо этого DEFINE.

Например:

я определяю свою навигацию, чтобы быть на основе PHP хэш дерева.Навигационная деталь будет иметь следующее:

А), если существует связь верхнего уровня, хэш-массив будет содержать элемент (суб массива) с надписью «навигационный лист»

б) навигацией лист будет содержать элементы с надписью «Display value», «link value» и «alt value». Эти элементы будут использоваться для создания тега привязки.

c) если элемент имеет подменю, в дополнение к содержанию «навигационного листа», будет присутствовать элемент «субнавигации». Элемент субнавигации будет иметь «навигационный лист», если он имеет отображаемый элемент навигации.

Затем вы можете написать функции/методы, которые отображают вашу навигацию, в зависимости от выбранного вами определения.

1

Что я буду делать, что-то вдоль этих линий:

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>'; 

Я оставлю семантику построения объекта, добавив детей и т.д. к пользователю ...

1

насчет переписывание функции нав следующим способом:

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); 
2

простейшим способом, ИМХО, это просто сделать рекурсивный вызов, и использовать дерево структурировано описание вашей навигации (то есть, вложенные массивы). Непроверенный пример код:

<?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); 
?> 
3

Не изобретайте колесо, используйте Zend_Navigation и вы будете счастливы.

+0

Использование его вне рамок всей структуры кажется менее простым. В любом случае сложнее использовать другие компоненты, такие как Mail или Log. – Lothar

+1

Теперь, когда я подробно рассмотрел его, не представляется возможным интегрировать Zend_Navigation в сайт без использования всех компонентов MVC этой структуры. Поправьте меня если я ошибаюсь. – Lothar

+0

Если вам не нужны модели и контроллеры zend. Вам не нужно даже использовать представление, но в этом случае вам нужно сделать некоторые трюки, чтобы легко использовать Zend_View_Helper_Navigation, что является важной частью Zend_Navigation. – takeshin

1

@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"; 
} 

Большое спасибо!

Интересно, какое влияние оказывает этот тип кода на скорости страницы tho. Несколько микросекунд в миллисекундах: D

Смежные вопросы