如何实现导航的“选中”项

1 投票
2 回答
1986 浏览
提问于 2025-04-17 08:00

我需要在网页上实现一个导航菜单,可能还会有好几层的标签。我之前在自己能控制CSS的时候都是用CSS来做的,但现在我在使用一个现成的CSS库(这次是Twitter的Bootstrap)时遇到了问题。

首先,这是我之前用的CSS方式。下面是一个示例HTML:

<html>
<head>
    <title>Example page</title>
</head>
<body class="articles">

<div class="navigation">
    <ul>
        <li class="frontpage"><a href="#">Frontpage</a></li>
        <li class="articles"><a href="#">Articles</a></li>
    </ul>
</div>

<p>Blah blah.</p>

</body>
</html>

... 还有CSS:

body.frontpage div.navigation li.frontpage,
body.articles div.navigation li.articles {
    background-color:red;
    color:white;
}

其实挺简单的。只需要在合适的时候改变一下body的类名就可以了。

现在,Bootstrap似乎是用类名来选择导航项(比如顶部栏、标签、药丸样式)。示例:

...
<div class="navigation">
    <ul class="tabs">
        <li class="active"><a href="#">Frontpage</a></li>
        <li><a href="#">Articles</a></li>
    </ul>
</div>
...

我最开始想在控制器里做类似这样的事情:

navigation = ('frontpage',)
# or
navigation = ('articles', 'categories', 'foo',)

然后把这个元组传给模板,但总觉得这样做有点“错”。

所以我的问题是:既然我必须在模板里打印类名的选择,那我该如何跟踪当前的位置(也就是这个页面在导航树中的位置),因为这个页面可能有多个层级的标签或其他导航项?有没有什么推荐的做法?

我在用Pyramid框架,路由风格配合Mako模板,但如果有通用的答案也很欢迎。

2 个回答

0

你可以使用在渲染过程中使用的系统值来通过访问变量view.__name__获取模板中的视图名称。

然后可以通过以下方式更改活动链接(下面的例子是用jinja2写的,但其他的应该也差不多)

<li {% if view.__name__ == "fixtures" %} class="active" {% endif %}>
  <a href="#">Link</a>
</li>

更多信息请查看 http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/templates.html#system-values-used-during-rendering

3

我做的事情和这个类似(也包括Pyramid和Bootstrap),不过我只处理一层导航。

我首先创建了一个“视图”对象,这个对象会在每次渲染时传递一些参数,比如标题、头部、获取数据等。例如:

class View_Controller(object):
    def __init__(self, request, **kwargs):
        self.request = request
        self.nav = kwargs.get('nav', None)

    @property
    def page(self):
        return request.GET.get('page', 1)

@view_config(route_name='home', renderer='templates/homepage.mako')
def Homepage_View(request):
    view = View_Controller(request, nav='homepage')
    stuff = DBSession.query(Stuff).all()
    return {'view': view, 'stuff': stuff}

在每个页面渲染时,我设置了一个名为nav的属性,但当没有激活的导航元素时,nav的值为None。我接着在Mako中创建了一个导航元素的模板:

<%def name="navelements(things)">
% for a in things:
<li${' class="active"' if nav == a[1] else '' | n }><a href="#">a[0]</a></li>
% endfor
</%def>

这里的“things”是一个包含所有导航元素的元组。[0]是显示名称,[1]是内部名称。这个“| n”是用来处理html字符的。例如:

<%! things = [['Frontpage', 'homepage'], ['Articles', 'arts'], ['Categories', 'cats'], ['Foo', 'foo']] %>

% if things:
<div class="navigation">
  <ul class="tabs">
    ${navelements(things)}
  </ul>
</div>
% else:
<hr />
% endif

现在,你可以在模板中或者通过视图在控制器中设置这些东西。我有一个“if things”的条件语句,以防你想要一个在每个页面上都调用的通用标签模板;只需在控制器中将things设置为None,就可以禁用标签。

这只是一个层级的标签,但你可以通过让things变成一个更复杂的列表来实现同样的效果。我会把things做得更复杂,这样看起来会像:

things = [['displayname1', 'elementname1', things1], ['displayname2', 'elementname2', things2], ...]

然后我会让navelements变成递归的(Mako不支持递归,所以我会复制navelements函数两次,让它们互相调用),并实现对多层导航的支持:

<%def name="navelements1(things, level=0)">
% for a in things:
<li${' class="active"' if nav[level] == a[1] else '' | n }><a href="#">a[0]</a></li>
   % if a[2]:
     <ul class="tabs">
       ${navelements2(a[2], level+=1)}
     </ul>
   % endif
% endfor
</%def>

这里的nav看起来像:

nav = ['frontpage', 'best', None, ...]

希望这能解答你的问题。只要确保你的列表长度正确,就不会出现越界错误。

撰写回答