简体   繁体   English

使用 python/flask 中的 twitter bootstrap css 更改链接的活动类

[英]Changing the active class of a link with the twitter bootstrap css in python/flask

I got the following html snippet from my page template.html .我从我的页面template.html中获得了以下 html 片段。

<ul class='nav'>
    <li class="active"><a href='/'>Home</a></li>
    <li><a href='/lorem'>Lorem</a></li>

    {% if session['logged_in'] %}
        <li><a href="/account">Account</a></li>
        <li><a href="/projects">Projects</a>
        <li><a href="/logout">Logout</a></li>
    {% endif %}

    {% if not session['logged_in'] %}
        <li><a href="/login">Login</a></li>
        <li><a href="/register">Register</a></li>
    {% endif %}
</ul>

As you can see on line 2, there's the class active.正如您在第 2 行看到的那样,该类处于活动状态。 This highlights the active tab with the twitter bootstrap css file.这会突出显示带有 twitter 引导 css 文件的活动选项卡。 Now, this will work fine if I would visit www.page.com/ but not when I would visit www.page.com/login for example.现在,如果我访问www.page.com/ ,这将正常工作,但当我访问www.page.com/login时就不行。 It would still highlight the home link as the active tab.它仍会将主页链接突出显示为活动选项卡。

Of course, I could easily do this with Javascript/jQuery but I'd rather not use that in this situation.当然,我可以使用 Javascript/jQuery 轻松地做到这一点,但在这种情况下我宁愿不使用它。

There's already a working solution for ruby on rails but I don't know how to convert that into python/jinja (I'm rather new to jinja/flask, never worked with ruby at all) ruby on rails 已经有一个可行的解决方案,但我不知道如何将其转换为 python/jinja(我对 jinja/flask 很陌生,根本没有使用过 ruby​​)

Have you looked at this ?你看过这个吗? https://jinja.palletsprojects.com/en/3.0.x/tricks/#highlighting-active-menu-items https://jinja.palletsprojects.com/en/3.0.x/tricks/#highlighting-active-menu-items

Highlighting Active Menu Items突出显示活动菜单项

Often you want to have a navigation bar with an active navigation item.通常,您希望有一个带有活动导航项的导航栏。 This is really simple to achieve.这真的很容易实现。 Because assignments outside of blocks in child templates are global and executed before the layout template is evaluated it's possible to define the active menu item in the child template:因为子模板中块之外的分配是全局的并且在评估布局模板之前执行,所以可以在子模板中定义活动菜单项:

{% extends "layout.html" %}
{% set active_page = "index" %}

The layout template can then access active_page .然后布局模板可以访问active_page Additionally it makes sense to define a default for that variable:此外,为该变量定义默认值是有意义的:

{% set navigation_bar = [
    ('/', 'index', 'Index'),
    ('/downloads/', 'downloads', 'Downloads'),
    ('/about/', 'about', 'About')
] -%}

{% set active_page = active_page|default('index') -%}
...
<ul id="navigation">
    {% for href, id, caption in navigation_bar %}
    <li{% if id == active_page %} class="active"{% endif
    %}><a href="{{ href|e }}">{{ caption|e }}</a>
    </li>
{% endfor %}
</ul>

Here is another simpler way if you have menus distributed all over the page.如果您的菜单分布在整个页面,这是另一种更简单的方法。 This way uses inline if statements to print out the class active .这种方式使用内联 if 语句打印出active类。

<ul>

<li class="{{ 'active' if active_page == 'menu1' else '' }}">
<a href="/blah1">Link 1</a>
</li>

<li class="{{ 'active' if active_page == 'menu2' else '' }}">
<a href="/blah2"> Link 2 </a>
</li>

</ul>

Class active is for highlighting类 active 用于突出显示

You still need to set the variable on every page to mark them您仍然需要在每个页面上设置变量来标记它们

{% extends "master.html" %}
{% set active_page = "menu1" %}

or或者

{% set active_page = "menu2" %}

For jinja/flask/bootstrap users:对于jinja/flask/bootstrap用户:

If you define your nav like they did in the blog example http://getbootstrap.com/examples/blog/ simply assign ids to your links that match your url_for arguments and you just need to modify the layout-template, the rest just works #magic.如果您像在博客示例http://getbootstrap.com/examples/blog/中那样定义导航,只需将 id 分配给与您的url_for参数匹配的链接,您只需要修改布局模板,其余的就可以了#魔法。

<nav class="blog-nav">
  <a id="allposts"  class="blog-nav-item" href="{{ url_for('allposts')}}">All Posts</a>
  <a id="index"     class="blog-nav-item" href="{{ url_for('index')}}">Index</a>
  <a id="favorites" class="blog-nav-item" href="{{ url_for('favorites')}}">Favorites</a>
</nav>

At the bottom of your base/layout template just add this在你的基础/布局模板的底部添加这个

<script>
  $(document).ready(function () {
  $("#{{request.endpoint}}").addClass("active"); })
</script>

and the right elements will be set active.并且正确的元素将被激活。

EDIT: If you have a layout with elements in a list, like this:编辑:如果您的布局包含列表中的元素,如下所示:

<nav class="blog-nav">
  <ul class="nav navbar-nav">
    <li>
        <a id="allposts"  class="blog-nav-item" href="{{ url_for('allposts')}}">All Posts</a>
    </li>
    <li>
        <a id="index"     class="blog-nav-item" href="{{ url_for('index')}}">Index</a>
    </li>
    <li>
        <a id="favorites" class="blog-nav-item" href="{{ url_for('favorites')}}">Favorites</a>
    </li>
  </ul>
</nav>

use the parent() function to get the li element instead of the link.使用parent()函数获取 li 元素而不是链接。

<script>
    $(document).ready(function () {
    $("#{{request.endpoint}}").parent().addClass("active"); })
</script>

we can make class active by using jinja if statements我们可以使用 jinja if 语句让课堂活跃起来

<ul class="nav navbar-nav">
     <li class="{% if request.endpoint=='home' %}active{%endif %}"><a href="{{  url_for('home') }}">home</a></li>
     <li class="{% if request.endpoint=='add_client' %}active{%endif %}"><a href="{{  url_for('add_client') }}">Add Report</a></li>
    </li>
  </ul>

I liked @philmaweb 's approach, but there's really no reason to require duplicating the endpoint in the id of each element.我喜欢@philmaweb的方法,但实际上没有理由要求在每个元素的 id 中复制端点。

base.js: base.js:

$(document).ready(function () {
    var scriptElement = $('#baseScript')[0];
    var path = scriptElement.getAttribute('data-path');
    $('a[href="'+path+'"]').addClass("active");
});

base.html base.html

<script id="baseScript" src="{{ url_for('static', filename='js/base.js') }}"
data-path="{{ request.path }}"></script>

Why not just put this script inline?为什么不把这个脚本内联呢? You could, of course, but allowing inline JS is a security nightmare .当然可以,但允许内联 JS 是一场安全噩梦 You should be using a CSP on your site (eg Flask-Talisman ) which will not allow inline JS.您应该在您的网站上使用不允许内联 JS 的 CSP(例如Flask-Talisman )。 With data-* attributes, it's not hard to do this in a secure way.使用data-*属性,以安全的方式执行此操作并不难。

NB: If you have multiple links leading to the same, current page and you want only ONE of them to be marked "active"—then this approach may not work for you.注意:如果您有多个链接指向同一个当前页面,并且您只想将其中一个标记为“活动”,那么这种方法可能不适合您。

I tried different solution for this for the solution 1st by Codegeek didn't work as I have multiple Ul and li under it so I just include my navbar in template.html我为此尝试了不同的解决方案, Codegeek的解决方案 1 不起作用,因为我在它下面有多个 Ul 和 li,所以我只在 template.html 中包含我的导航栏

{% include 'sidebar.html' %}

then in Navbar file in the li class you can set active with help of "request.endpoint" but then again it will return you entire route instead use split and take last route name and set active if same for exmaple然后在 li 类的 Navbar 文件中,您可以在“request.endpoint”的帮助下将其设置为活动,但随后它会再次返回您整个路线,而不是使用拆分并获取最后一个路线名称并设置活动(如果相同)例如

 <li class="{% if request.endpoint.split('.')[1] == 'index' %} active {% else %}  {% endif %}">

request.endpoint.split('.')[1] will return the route eg localhost/example. request.endpoint.split('.')[1]将返回路由,例如 localhost/example。 You will get example which you can compare and use.您将获得可以比较和使用的示例。 If you won't split and use request.endpoint than you will get 'file.example' (entire route).如果您不拆分并使用 request.endpoint ,那么您将获得“file.example”(整个路线)。

Add the following CSS somewhere on your page:在页面的某处添加以下 CSS:

a[href $= {{ page_name|default("'/'"|safe) }}]{ [INSERT YOUR ACTIVE STYLING HERE] }

Now, on each template define page_name , for example:现在,在每个模板上定义page_name ,例如:

{% extends "template.html" %} {% set page_name = "gallery" %}

This seems much simpler and easier to build on, than other options.这似乎比其他选项更简单、更容易构建。

EDIT:编辑:

Almost 1 year later I'm returning to make this a much simpler fix, because setting the page name on every page is pretty inefficient.差不多 1 ​​年后,我回来做这个更简单的修复,因为在每个页面上设置页面名称效率非常低。

Instead create a function like so:而是像这样创建一个函数:

@app.context_processor
def context_processor():
    out = {}
    out['request'] = request # Make sure you import request from flask
    return out

This will allow you to pass variables implicitly to jinja, in this case we are passing the request for access to request.url_rule which contains the route the user is accessing.这将允许您将变量隐式传递给 jinja,在这种情况下,我们将访问请求传递给request.url_rule ,其中包含用户正在访问的路由。 In the previous version, we just change {{ page_name|default("'/'"|safe) }} to "{{ request.url_rule|safe }}" .在之前的版本中,我们只是将{{ page_name|default("'/'"|safe) }}更改为"{{ request.url_rule|safe }}" Much cleaner.干净多了。

I did not want to have to define the ID in the child pages, as many of the links I have do not have a specific child template.我不想在子页面中定义 ID,因为我拥有的许多链接都没有特定的子模板。

Using the request.base_url and if it matches the _external url_for the route, then render that nav item as active.使用request.base_url并且如果它与路由的_external url_for匹配,则将该导航项呈现为活动状态。

{% set nav_items = [
    ("public.home", "Home"),
    ("public.downloads", "Downloads"),
    ("public.about", "About")
    ("account.login", "Login"),
 ]
 -%}

...

   <ul class="navbar-nav mr-auto">
   {% for route, display_text in  nav_items %}
     <li class={% if request.base_url == url_for(route, _external=True) %}"nav-item active"{% else %}"nav-item"{% endif %}>
       <a class="nav-link" href="{{ url_for(route) }}">{{ display_text }}
     {% if request.base_url == url_for(route, _external=True) %}<span class="sr-only">(current)</span>{% endif %}
       </a>
     </li>
   {% endfor %}
   </ul>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM