Bootstrap 3的动态菜单生成器:项目和链接

tech2023-09-06  97

In part 1, we prototyped the end product and wrote the main Menu class, which serves as the menu manager – a container to hold all sub-units (items and links). In this part, we’ll build the remainder of the classes and demonstrate the menu builder’s usage.

在第1部分中,我们对最终产品进行了原型设计,并编写了主Menu类,该类用作菜单管理器–一个容纳所有子单元(项目和链接)的容器。 在这一部分中,我们将构建其余的类,并演示菜单构建器的用法。

项目 (Item)

Represents our menu items as independent objects.

将我们的菜单项表示为独立的对象。

Create a new file called item.php and paste in the following code:

创建一个名为item.php的新文件,并粘贴以下代码:

item.php

item.php

class Item { protected $manager; protected $id; protected $pid; protected $meta; protected $attributes = array(); public $link; //...

$manager stores a reference to the menu manager (Menu object). This makes us able to use menu manager methods within Item context.

$manager存储对菜单管理器( Menu对象)的引用。 这使我们能够在Item上下文中使用菜单管理器方法。

$id stores the item’s id.

$id存储项目的ID。

$pid stores item’s parent id if it has one otherwise it’ll be set to null.

$pid存储项目的父ID(如果有的话),否则将设置为null 。

$meta an array for storing extra data with each item.

$meta一个数组,用于存储每个项目的额外数据。

$attributes an array of HTML attributes.

$attributes分配HTML属性数组。

$link stores an instance of class Link.

$link存储类Link的实例。

__construct(管理员,标题,URL,属性,PID) (__construct(manager, title, url, attributes, pid))

Initializes the attributes.

初始化属性。

public function __construct($manager, $title, $url, $attributes = array(), $pid = 0) { $this->manager = $manager; $this->id = $this->id(); $this->pid = $pid; $this->title = $title; $this->attributes = $attributes; // Create an object of type Link $this->link = new Link($title, $url); }

添加(标题,选项) (add(title, options))

Class Item has an add() method as well (just like the menu manager). In fact this method doesn’t create items on its own. It gets the arguments, adds a pid key to $options and calls add() of the menu manager.

类Item也具有add()方法(就像菜单管理器一样)。 实际上,此方法不会自行创建项目。 它获取参数,将pid键添加到$options并调用菜单管理器的add() 。

public function add($title, $options) { if( !is_array($options) ) { $options = array('url' => $options); } $options['pid'] = $this->id; return $this->manager->add( $title, $options ); }

This gives us the power to create sub items in a more semantic way rather than explicitly defining a pid:

这使我们能够以更语义的方式创建子项,而不是显式定义pid :

$menu = new Menu; $about = $menu->add('About', 'about'); // We write it this way $about->add('What we do?', 'what-we-do'); // instead of: // $menu->add('What we do?', array('url' => 'what-we-do', 'pid' => $about->get_id()));

ID() (id())

Generates a unique id for the Item. We use this identifier to refer to the item later.

生成项目的唯一ID。 我们稍后使用此标识符来引用该项目。

protected function id() { return $this->manager->length() + 1; }

In fact id() calls length() of the menu manager and increments it by 1.

实际上, id()调用菜单管理器的length()并将其递增1。

get_id() (get_id())

We also need to create a getter method to return the id when needed:

我们还需要创建一个getter方法来在需要时返回id:

public function get_id() { return $this->id; }

get_pid() (get_pid())

Items might have pid (parent’s id). pid value might be null or id of another item.

项目可能具有pid (父母的ID)。 pid值可能为null或另一个项目的ID。

Items with pid set to null are the items at root level.

pid设置为null的项目是根级别的项目。

We need to create a getter to return Item’s pid as well:

我们还需要创建一个吸气剂以返回Item的pid :

public function get_pid() { return $this->pid; }

有孩子() (hasChildren())

Checks whether the item has any children or not.

检查项目是否有子级。

public function hasChildren() { return (count($this->manager->whereParent($this->id))) ? true : false; }

It calls whereParent() via the manager.

它通过管理器调用whereParent() 。

儿童() (children())

Fetches children of the item.

获取项目的子项。

public function children() { return $this->manager->whereParent($this->id); }

属性(键,值) (attributes(key, value))

Gets or sets item’s attributes.

获取或设置项目的属性。

public function attributes() { $args = func_get_args(); if(is_array($args[0])) { $this->attributes = array_merge($this->attributes, $args[0]); return $this; } elseif(isset($args[0]) && isset($args[1])) { $this->attributes[$args[0]] = $args[1]; return $this; } elseif(isset($args[0])) { return isset($this->attributes[$args[0]]) ? $this->attributes[$args[0]] : null; } return $this->attributes; }

As you see attributes() returns different types of results according to the arguments given:

如您所见, attributes()根据给定的参数返回不同类型的结果:

Sets attribute if both $key and $value given.

如果同时指定了$key和$value则设置属性 。

Sets array of attributes if $key is an array.

如果$key是数组,则设置属性数组。

Gets attribute if only $key given.

如果仅给出$key则获取属性 。

Gets all attributes if no argument given.

如果未提供参数,则获取所有属性 。

meta($ key,$ value) (meta($key, $value))

Meta stores extra data about the item. It can be any kind of data from placement order to required permissions.

元数据存储有关该项目的额外数据。 它可以是从布置顺序到所需权限的任何类型的数据。

public function meta() { $args = func_get_args(); if(is_array($args[0])) { $this->meta = array_merge($this->meta, $args[0]); return $this; } elseif(isset($args[0]) && isset($args[1])) { $this->meta[$args[0]] = $args[1]; return $this; } elseif(isset($args[0])) { return isset($this->meta[$args[0]]) ? $this->meta[$args[0]] : null; } return $this->meta; }

meta() works exactly like attributes().

meta()工作方式与attributes()完全相同。

Now let’s move on to the Link class.

现在让我们进入Link类。

Class Link is a simple class consisting of several getter and setter methods.

类Link是一个简单的类,由几个getter和setter方法组成。

Link has three attributes:

Link具有三个属性:

text link text

文字链接文字

url link URL

网址链接网址

attributes link attributes

属性链接属性

link.php

链接

class Link { public $text; public $url; public $attributes; //....

__construct(文本,URL,属性) (__construct(text, url, attributes))

When we create an object of type Link, the constructor method binds the arguments to the attributes listed above:

当我们创建Link类型的对象时,构造方法将参数绑定到上面列出的属性:

public function __construct($text, $url, $attributes = array()) { $this->text = $text; $this->url = $url; $this->attributes = $attributes; }

字符串get_url() (string get_url())

Returns link url.

返回链接URL。

public function get_url() { return $this->url; }

字符串get_text() (string get_text())

Returns the link text

返回链接文本

public function get_text() { return $this->text; }

You’ll encounter situations when you need to append or prepend some content to the anchor text like a caret sign for drop-downs or a graphical icon. To achieve this, we will create two simple functions that do just the thing for us.

当您需要在锚文本中添加或添加一些内容(例如,下拉菜单的插入符号或图形图标)时,会遇到这种情况。 为了实现这一目标,我们将创建两个简单的函数,它们仅对我们有用。

追加(内容) (append(content))

append adds content to the link text:

append将内容添加到链接文本:

public function append($content) { $this->text .= $content; return $this; }

前置(内容) (prepend(content))

prepend prepends content to the link:

prepend预先考虑内容的链接:

public function prepend($content) { $this->text = $content . $this->text; return $this; }

属性(键,值) (attributes(key, value))

Like Items It would be fantastic if we could define HTML attributes for anchors.

Like Items如果可以为锚点定义HTML属性,那将是很棒的。

public function attributes($key = null, $value = null) { $args = func_get_args(); if(is_array($args[0])) { $this->attributes = array_merge($this->attributes, $args[0]); return $this; } elseif(isset($args[0]) && isset($args[1])) { $this->attributes[$args[0]] = $args[1]; return $this; } elseif(isset($args[0])) { return isset($this->attributes[$args[0]]) ? $this->attributes[$args[0]] : null; } return $this->attributes; }

I think this method is familiar to you since we’ve created it earlier.

我认为这种方法对您来说很熟悉,因为我们之前已经创建了它。

With this, our Menu Builder is complete!

这样,我们的菜单构建器就完成了!

用法 (Usage)

We usually create one PHP file per class definition, so, to use our menu builder we need to include each file at the beginning of our script.

通常,我们为每个类定义创建一个PHP文件,因此,要使用菜单构建器,我们需要在脚本的开头包含每个文件。

Rather than including all the three files, I’m going to take advantage of class autoloading feature in PHP: __autoload(string $class). This feature helps us avoid writing a long list of includes at the beginning of each script.

而不是包括所有三个文件,我将利用PHP中的类自动加载功能: __autoload(string $class) autoload __autoload(string $class) 。 此功能有助于我们避免在每个脚本的开头编写一长串包含项。

__autoload() is automatically called in case you are trying to use a class or interface which hasn’t been defined yet.

如果您尝试使用尚未定义的类或接口,则会自动调用__autoload() 。

__autoload receives the class name as argument.

__autoload接收类名称作为参数。

This is how we’re going to use it:

这就是我们将如何使用它:

function __autoload($class) { require_once(strtolower($class) . '.php'); }

Name this file autoload.php and include it in your script.

将此文件命名为autoload.php并将其包含在脚本中。

Please note that this is probably less than ideal. In a real project, your autoloading needs would be taken care of by Composer or the framework’s autoloader. You can see this on the Github link we provided – the project is fully developed there, and fine tuned for use with Laravel, among others.

请注意,这可能不理想。 在实际的项目中,Composer或框架的自动加载器将满足您的自动加载需求。 您可以在我们提供的Github链接上看到这一点–该项目已在此处完全开发,并进行了微调以与Laravel等一起使用。

Next, let’s create a menu to test our menu builder out:

接下来,让我们创建一个菜单来测试菜单构建器:

<?php require_once('autoload.php'); $menu = new Menu; $about = $menu->add('About', 'about'); // since this item has sub items we append a caret icon to the hyperlink text $about->link->append(' <span class="caret"></span>'); // we can attach HTML attributes to the hyper-link as well $about->link->attributes(['class' => 'link-item', 'target' => '_blank']); // Adding an attribute to the item wrapper itself $about->attributes('data-model', 'info'); $about->add('Who we are?', array('url' => 'who-we-are', 'class' => 'navbar-item whoweare')); $about->add('What we do?', array('url' => 'what-we-do', 'class' => 'navbar-item whatwedo')); $about->add('Goals', array('url' => 'goals', 'display' => false)); $menu->add('Portfolio', 'portfolio'); $menu->add('Contact', 'contact'); // we're only going to hide items with `display` set to **false** $menu->filter( function($item){ if( $item->meta('display') === false) { return false; } return true; }); // Now we can render the menu as various HTML entities: echo $menu->asUl( attribute('class' => 'ausomw-ul') ); //OR echo $menu->asOl( attribute('class' => 'ausomw-ol') ); // OR echo $menu->asDiv( attribute('class' => 'ausomw-div') ); ?>

Done!

做完了!

Bootstrap 3导航栏 (Bootstrap 3 Navbar)

The final step is to use our menu builder to create dynamic Bootstrap Navbars.

最后一步是使用菜单构建器来创建动态的Bootstrap Navbars。

First of all, we need to create a function that populates our items in a Bootstrap friendly format because the existing render method doesn’t do this for us.

首先,我们需要创建一个以Bootstrap友好格式填充项目的函数,因为现有的render方法无法为我们完成此任务。

I name this function bootstrapItems() (I couldn’t really think of a better name, feel free to name it whatever you please).

我将此函数命名为bootstrapItems() (我真的想不出更好的名称,可以随便命名。)

You can put this function in any file you like as long as it is loaded at application startup. Alternatively you can extend the class Menu and add this method to the class. In this example, I place it in autoloader.php (as a helper function) to make sure it is always available to me.

只要在应用程序启动时将其加载,就可以将该函数放置在所需的任何文件中。 另外,您可以扩展类Menu并将此方法添加到类中。 在此示例中,我将其放置在autoloader.php (作为辅助函数),以确保它始终对我可用。

function bootstrapItems($items) { // Starting from items at root level if( !is_array($items) ) { $items = $items->roots(); } foreach( $items as $item ) { ?> <li <?php if($item->hasChildren()): ?> class="dropdown" <?php endif ?>> <a href="<?php echo $item->link->get_url() ?>" <?php if($item->hasChildren()): ?> class="dropdown-toggle" data-toggle="dropdown" <?php endif ?>> <?php echo $item->link->get_text() ?> <?php if($item->hasChildren()): ?> <b class="caret"></b> <?php endif ?></a> <?php if($item->hasChildren()): ?> <ul class="dropdown-menu"> <?php bootstrapItems( $item->children() ) ?> </ul> <?php endif ?> </li> <?php } }

Since it’s just for educational purpose I didn’t use a template engine here as It’s beyond the scope of this tutorial. You can use the template engine of your choice to separate logic from presentation and make your code more readable.

由于这只是出于教育目的,因此我在这里不使用模板引擎,因为这超出了本教程的范围。 您可以使用所选的模板引擎将逻辑与表示分离,并使代码更具可读性。

Let’s see what BootstrapItems does behind the scenes.

让我们看看BootstrapItems在幕后做什么。

First of all, it checks whether the given argument is an array or not. If it’s not, it fetches the items at root level and iterates over them. On each iteration it checks also if the current element has any children and if the element does have children, it will call itself passing the element’s children as a parameter. This process is repeated until it renders all the items to the deepest level.

首先,它检查给定的参数是否为数组。 如果不是,它将在根级别获取项目并对其进行迭代。 在每次迭代中,它还会检查当前元素是否有任何子元素,以及该元素是否确实有子元素,它将通过将元素的子元素作为参数进行调用。 重复此过程,直到将所有项目渲染到最深层次。

Okay, now that we are able to generate the items in a Bootstrap friendly format, let’s register some items:

好的,现在我们已经能够以Bootstrap友好格式生成项目,让我们注册一些项目:

<?php require_once('autoload.php'); // $menu #1 $main = new Menu; $main->add('<span class="glyphicon glyphicon-home"></span>', ''); $about = $main->add('about', 'about'); $about->add('Who we are?', 'who-we-are?'); $about->add('What we do?', 'what-we-do?'); $main->add('Services', 'services'); $main->add('Portfolio', 'portfolio'); $main->add('Contact', 'contact'); // menu #2 $user = new Menu; $user->add('login', 'login'); $profile = $user->add('Profile', 'profile'); $profile->add('Account', 'account') ->link->prepend('<span class="glyphicon glyphicon-user"></span> '); $profile->add('Settings', 'settings') ->link->prepend('<span class="glyphicon glyphicon-cog"></span> '); ?>

And here’s our boilerplate code:

这是我们的样板代码:

<nav class="navbar navbar-default" role="navigation"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Sitepoint</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <?php echo bootstrapItems($main); ?> </ul> <form class="navbar-form navbar-left" role="search"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <?php echo bootstrapItems($user); ?> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav>

Because we have two different menus, we call BootstrapItems two times in our Bootstrap template.

因为我们有两个不同的菜单,所以我们在Bootstrap模板中两次调用BootstrapItems 。

Don’t forget to have jquery and bootstrap CSS and JS files loaded in your page before testing out the result!

测试结果之前,请不要忘记在页面中加载了jquery和bootstrap CSS和JS文件!

结论 (Conclusion)

We implemented a Menu manager, Items and Links in three class definitions for the sake of flexbility. We also stored a reference to the manager along with each item. This reference allowed us to access the manager from within Item context.

为了灵活起见,我们在三个类定义中实现了菜单管理器,项目和链接。 我们还与每个项目一起存储了对经理的引用。 此引用使我们可以从Item上下文中访问管理器。

You can use this menu builder in any form you like as long as you use the right methods.

您可以使用任何喜欢的形式使用此菜单构建器,只要您使用正确的方法即可。

If you’re using Laravel 4, you can get laravel-menu which is implemented based on the methods described in this tutorial while providing more features, otherwise, see the full code of our built Menu Builder: fleximenu.

如果您使用的是Laravel 4,则可以获取laravel-menu ,该菜单是根据本教程中描述的方法实现的,同时提供了更多功能,否则,请参见构建的Menu Builder的完整代码: fleximenu 。

Happy coding!

祝您编码愉快!

翻译自: https://www.sitepoint.com/dynamic-menu-builder-bootstrap-3-item-link/

相关资源:bootstrap树形下拉框 下拉框树形菜单
最新回复(0)