Spis treści:

Kategoria:HTMLjQuery


Automatyczne menu w HTML - jQuery

Ostatnio zajmowałem się automatycznym tworzeniem przypisów dolnych (wpis można znaleźć tutaj: Automatyczne wstawianie przypisów dolnych HTML/jQuery). Pisałem przy okazji, że do tematu najprawdopodobniej powrócę, bo jest dość atrakcyjny. Tym razem, jak wskazuje nagłówek, zajmę się automatycznym spisem treści.

Gdy zastanawiałem się, jaki będzie najłatwiejszy sposób (najłatwiejszy z punktu późniejszego wstawiania na stronę, nie wcześniejszego programowania), przypomniał mi się pakiet Office i inne tego typu programy. Tam spis treści tworzy się najczęściej na podstawie nagłówków. Pisząc tekst, poprzedzamy go nagłówkami (ang. header). Znawcy HTML już pewnie wiedzą - HTML również posiada nagłówki w postaci znaczników h1, h2, h3 i tak dalej, aż do h6. Tyle przewiduje, przynajmniej na dzień dzisiejszy, standard. Swoją drogą, trudno przypuszczać, by komuś rzeczywiście aż tyle poziomów zagłębienia nagłówków było potrzebne.

Podobnie jak we wspomnianym artykule o przypisach dolnych, także i tutaj skorzystam z biblioteki jQuery.

Planowanie automatycznego menu w HTML

Plan wydaje się dość prosty. Miejsce, gdzie powinien pojawić się automatyczny spis treści, będzie oznaczone poprzez element o identyfikatorze TableOfContents. Użycie identyfikatora uniemożliwia stworzenie menu w dwóch (i więcej) miejscach, ale myślę, że przerobienie kodu i realizacja takiego zadania nie będzie już trudna. Wystarczy elementy oznaczyć przy pomocy klasy.

Czym by było automatyczne menu bez możliwości przechodzenia do pożądanych akapitów? Niczym. Dlatego wypadałoby jako elementy menu wstawić hiperłącza, które wskazywałyby konkretne nagłówki. Jak je wskazywać? Oczywiście poprzez hiperłącza wewnętrzne, czyli na podstawie identyfikatora.

Kolejne pytanie: czy zatem konieczne jest wstawienie identyfikatorów do nagłówków? Jasne, że nie. Identyfikatory wstawimy sami, automatycznie. Czy jest coś jeszcze, na co powinniśmy na tym etapie zwrócić uwagę? Aby za bardzo nie mieszać, na tym etapie się zatrzymamy. Udoskonalaniem automatycznego menu zajmę się później.

Implementacja w jQuery

Przypomnę, że algorytm zaimplementowany jest w jQuery, więc należy na testowanej stronie, najlepiej w nagłówku, umieścić odwołanie do odpowiedniego pliku biblioteki, podobne do zaprezentowanego poniżej:

<script src="jquery-1.3.2.min.jstype="text/javascript"></script>

Założę, że na stronie będą tylko nagłówki h1, h2, h3 i h4. To dla uproszczenia - samo rozszerzenie do h6 nie powinno być trudne. Jak zwykle w jQuery, zadanie rozpoczyna się od wybrania elementów, na których chcemy wykonać akcję - będą to właśnie nasze nagłówki. Do każdego z nich dodamy identyfikator, i dla każdego z nich wstawimy hiperłącze w elemencie określającym pozycję menu. Skrypt dla pierwszej wersji menu pokazany jest poniżej:

<script type="text/javascript">
$(document).ready(function(){
  var i=1;
  $('h1,h2,h3,h4').each(function(){
    $(this).attr('id''autoMenu'+i);
    $('#TableOfContents').append('<div class="AutoMenuItem"><a href="#autoMenu'+i+'">'+$(this).html()+'</a></div>');
    i++;
  });
});
</script>

To wystarczy, aby zawartość poszczególnych nagłówków umieścić w elemencie określającym pozycję menu. Aby o nim nie zapomnieć, zamieszczę przykład takiego wskaźnika poniżej:

<div id="TableOfContents"></div>

Bez niego efekty nie będą widoczne, bo skrypt nie będzie wiedział, gdzie umieścić wyniki. Najczęściej znacznik będzie umieszczany tuż przed tekstem artykułu, ale nic nie stoi na przeszkodzie, aby umieścić go gdzieś z boku, lub na jakimś fruwającym panelu, aby był cały czas dostępny.

Warto zwrócić uwagę na numerację identyfikatorów w postaci autoMenuX, gdzie X to kolejny numer nagłówka. Oprócz tego, co zostało zaplanowane, wstawiłem każdy element w znacznik div (aby dało się nimi łatwiej zarządzać z poziomu CSS i aby domyślnie zajmowały nową linię) oraz do każdego z tych znaczników przypisałem klasę AutoMenuItem - również w celu łatwiejszego zarządzania tymi elementami z poziomu CSS/JavaScript.

Wykluczanie elementów z menu

Może zaistnieć taka sytuacja, że pewnych elementów, będących nagłówkami, w menu nie chcemy. Ja akurat korzystam z nagłówka przed spisem treści. Dziwnie to wygląda, gdy w spisie treści jest odwołanie do spisu treści. Uznałem, że w takich przypadkach nagłówek należy oznaczyć - będzie to realizowane przy pomocy klasy DisableTableOfContents.

Ingerencja w istniejący skrypt będzie minimalna. Cały kod, z wyróżnionymi linijkami, które dodałem, pokazany jest na poniższym listingu:

<script type="text/javascript">
$(document).ready(function(){
  var i=1;
  $('h1,h2,h3,h4').each(function(){
    if ($(this).hasClass('DisableTableOfContents'))
      return;

    $(this).attr('id''autoMenu'+i);
    $('#TableOfContents').append('<div class="AutoMenuItem"><a href="#autoMenu'+i+'">'+$(this).html()+'</a></div>');
    i++;
  });
});
</script>

Rozwiązanie jest bardzo proste - jeżeli nagłówek posiada klasę DisableTableOfContents, pomiń jego dalsze przetwarzanie.

Wcięcia nagłówków bez udziału CSS

Tak utworzone menu jest, nie bójmy się użyć tego słowa, płaskie, nijakie. Nie po to wstawiamy różne poziomy nagłówków, aby teraz wszystko utracić. Jednym z pomysłów jest takie rozwiązanie, które dla niższych poziomów wstawi białe znaki, proporcjonalnie do poziomu. Jest to rozwiązanie mało elestyczne, ale nie wymaga żadnych dodatkowych ingerencji w plikach CSS. Przyjrzyjmy się zatem skryptowi zaprezentowanemu poniżej:

<script type="text/javascript">
$(document).ready(function(){
  var i=1;
  $('h1,h2,h3,h4').each(function(){
    if ($(this).hasClass('DisableTableOfContents'))
      return;

    var spacing=this.tagName.substring(1);
    var indent = '';
    while (spacing>1){
      indent+='&nbsp; ';
      spacing--;
    }
    if (indent.length>0)
      indent='<span>'+indent+'</span>';

    $(this).attr('id''autoMenu'+i);
    $('#TableOfContents').append('<div class="AutoMenuItem">'+indent+'<a href="#autoMenu'+i+'">'+$(this).html()+'</a></div>');
    i++;
  });
});
</script>

Rozwiązanie działa, ale nie jest to szczyt możliwości. A gdyby tak ktoś zechciał znacznie badziej upiększyć menu? Gdyby zechciał zróżnicować wielkość czcionki, wcięcia, dodać obrazki? Mógłby to zrobić za pomocą CSS.

Wcięcia automatycznego menu przy pomocy CSS

Obecna forma nie nadaje się do zastosowania, bo nie da się przy pomocy CSS określić poziomu danego elementu. Jak to naprawić? Dodać coś, co pozwoli ten poziom określić. W zaprezentowanym poniżej przykładzie dodano, zamiast obecnej wcześniej klasy AutoMenuItem, dodam teraz klasy AutoMenuLevelX, gdzie X będzie określało poziom zagłębienia, pobierany dokładnie tak samo jak w poprzednim przykładzie - jako drugi znak nazwy nagłówka hX. Popatrzmy na zaprezentowany poniżej listing realizujący to zadanie:

$(document).ready(function(){
  var i=1;
  $('h1,h2,h3,h4').each(function(){
    if ($(this).hasClass('DisableTableOfContents'))
      return;

    var spacing=this.tagName.substring(1);
    $(this).attr('id''autoMenu'+i);
    $('#TableOfContents').append('<div class="AutoMenuLevel'+spacing
      +'"><a href="#autoMenu'+i+'">'+$(this).html()+'</a></div>');
    i++;
  });
});

Teraz każdy poziom menu może być z łatwością wskazany przez CSS. Przykład pliku CSS pokazany jest poniżej:

<style type="text/css">
a{text-decoration: none;}
a:hover{text-decoration:underline;}
.AutoMenuLevel1 a{color:Black;}
.AutoMenuLevel2 a{color:Blue;}
.AutoMenuLevel3 a{color:Green;}
.AutoMenuLevel4 a{color:Red;}
 </style>

Aby łatwo było przetestować, każdy poziom menu ma inny kolor. Nie jest to rozsądne na stronie, ale jako przykład jest znakomite - proste i przejrzyste.

Kategoria:HTMLjQuery

, 2013-12-20

Brak komentarzy - bądź pierwszy

Dodaj komentarz
Wyślij
Ostatnie komentarze
bardo ciekawe , można dzięki takim wpisom dostrzec wędkę..
Bardzo dziękuję za jasne tłumaczenie z dobrze dobranym przykładem!
Dzieki za te informacje. były kluczowe
Dobrze wyjaśnione, dzięki !