Изображение гика

Блог питониста

Делаем navbar

5 ноября 2017 г.

Иногда нужно сделать navbar и переключать класс active на выбранной ссылке. Это можно сделать по-разному, расскажу об одном решении. Допустим у нас есть простое Flask - приложение:

 1 from flask import Flask, render_template
 2 app = Flask(__name__)
 3 
 4 
 5 @app.route('/')
 6 def main():
 7     return render_template('base.html')
 8 
 9 
10 @app.route('/about')
11 def about():
12     return render_template('base.html')

И base.html:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="UTF-8">
 5   <title>Document</title>
 6 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
 7 <link rel="stylesheet" href="{{ url_for('static',filename='css/mysite.css') }}">
 8 </head>
 9 <body>
10 
11   <nav class="nav">
12     <a class="nav-link" href="/">Блог</a>
13     <a class="nav-link" href="/about">Об авторе</a>
14   </nav>
15 
16   <script
17     src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
18     integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
19     crossorigin="anonymous"></script>
20   <script src="{{ url_for('static',filename='js/mysite.js') }}"></script>
21 </body>
22 </html>

mysite.css:

1 .active {
2     background-color: grey;
3 }

И хочется добавлять класс active при клике на каждую ссылку в navbar'e. Можно использовать передачу переменных в шаблон:

1 @app.route('/')
2 def main():
3     return render_template('base.html', tab="")
4 
5 
6 @app.route('/about')
7 def about():
8     return render_template('base.html', tab="about")
1 <nav class="nav">
2   <a class="nav-link {% if tab == "" %}active{% endif %}" href="/">Блог</a>
3   <a class="nav-link {% if tab == "about" %}active{% endif %}" href="/about">Об авторе</a>
4 </nav>

Но можно ведь использовать js, сначала хочется сделать что-то вроде (mysite.js):

1 var selector = '.nav-link';
2 $(selector).on('click', function(){
3     $(selector).removeClass('active');
4     $(this).addClass('active');
5 });

Но это не будет работать, потому что после переключения класса страница обновится, и класс исчезнет со ссылки. Можно сделать по-другому:

1 <nav class="nav">
2   <a class="nav-link" href="/">Блог</a>
3   <a class="nav-link" href="/about">Об авторе</a>
4 </nav>
 1 $(document).ready(function() {
 2     const regex = /http:\/\/.*\/(.*)/g;
 3     const match = regex.exec(window.location.href);
 4     // iterate over all and find match
 5     if (match) {
 6         $(".nav-link").each(function() {
 7             if ($(this).attr("href").slice(1) == match[1]) {
 8                 $(this).addClass("active");
 9             }
10         });
11     }
12     // set active first element
13     else {
14         $(".nav-link:first").addClass("active");
15     }
16 });

Тоесть используя  window.location.href получаем текущий адрес, регулярным выражением пытаемся получить правую часть адреса, если не получается, то ставим active на первую ссылку, в другом случае находим соответствующую ссылку и ставим класс ей.

Говорят, что если у тебя есть проблема, и ты ее решаешь с помощью регулярных выражений, то у тебя две проблемы. Пожалуй, лучше переписать этот код, не используя регулярки:

 1 $(document).ready(function() {
 2     const href = window.location.href.split('/');
 3     const last = href[href.length - 1];
 4     // iterate over all and find match
 5     if (last) {
 6 	    $(".nav-link").each(function() {
 7 	        if ($(this).attr("href").slice(1) == last) {
 8 	            $(this).addClass("active");
 9 	        }
10 	    });
11     }
12     // set active first element
13     else {
14         $(".nav-link:first").addClass("active");
15     }
16 });

Есть разные способы решить данную проблему, я описал некоторые из них, надеюсь для кого-то это было полезно.

Метки

js
Если вам понравился пост, можете поделиться им в соцсетях: