Μενού με ένδειξη τρέχουσας σελίδας

Κώδικας, πληροφορίες, ερωτήσεις και απαντήσεις σχετικές με την JavaScript.

Συντονιστές: WebDev Moderators, Super-Moderators

Απάντηση
Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Μενού με ένδειξη τρέχουσας σελίδας

Δημοσίευση από skeftomilos » 25 Μαρ 2005 23:53

Αυτό του άρθρο είναι συνέχεια του ομώνυμου άρθρου Μενού με ένδειξη τρέχουσας σελίδας (ASP) που εξετάζει τον τρόπο αποφυγής του να έχουμε αυτοαναφορικά links στις σελίδες μας. Σε αντίθεση με τις ASP σελίδες που είδαμε εκεί, εδώ θα κατεβάσουμε όλα τα links ατόφια στον browser και θα φροντίσουμε με ένα έξυπνο script να αντικαταστήσουμε το προβληματικό link με απλό κείμενο. Για την ακρίβεια θα κάνουμε κάτι διαφορετικό. Θα κρύψουμε το link ώστε να μην εμφανίζεται και θα προσθέσουμε λίγο κείμενο πριν το κρυμμένο link που θα πάρει οπτικά τη θέση του. Αλλά ας πάρουμε μία εικόνα του τι θέλουμε να πετύχουμε:


Εικόνα


Βλέπετε ότι το link Καλομοίρα έχει γίνει σκέτο κείμενο. Αυτό έγινε με κώδικα JavaScript που έτρεξε αμέσως μόλις ολοκληρώθηκε το φόρτωμα της σελίδας. Για αρχή ας πάρουμε μια ιδέα του HTML κώδικα της σελίδας:

Κώδικας: Επιλογή όλων

<html>
  <head>
    <title>Καλομοίρα</title>
    <script type="text/javascript" src="menu.js"></script>
  </head>
  <body onLoad="disableCurrentLink&#40;&#41;">
    <h2>Καλομοίρα</h2>
    <div id="menu">
      <a href="paparizou.htm">Παπαρίζου</a> |
      <a href="kalomoira.htm">Καλομοίρα</a> |
      <a href="hi-5.htm">Χάι Φάιβ</a>
    </div>
  </body>
</html>
Σε σχέση με τις σελίδες ASP που είδαμε στην Server-side περίπτωση, εδώ υπάρχει περισσότερος κώδικας. Ο λόγος είναι ότι τα links περιέχονται μέσα στη σελίδα. Θα μπορούσαμε βέβαια να χρησιμοποιήσουμε server-side-include (SSI) αλλά ας υποθέσουμε ότι για κάποιο λόγο δεν υπάρχει αυτή η δυνατότητα και όλα πρέπει να γίνουν στον browser. Τα links θα επαναλαμβάνονται σε όλες τις σελίδες, αλλά θέλουμε τουλάχιστον να γλιτώσουμε από τον κόπο να αντικαθιστούμε το αυτοαναφορικό link με κείμενο χειρονακτικά. Γι αυτό και έχουμε προσθέσει ένα χειριστή συμβάντος onLoad στο tag <body> ο οποίος τρέχει τη ρουτίνα disableCurrentLink() μόλις ολοκληρωθεί το φόρτωμα του HTML κώδικα. Η ρουτίνα αυτή βρίσκεται στο αρχείο menu.js που έχουμε συμπεριλάβει με το tag <script>. Το αρχείο αυτό εκτός από το όνομα δεν έχει καμία άλλη σχέση με το ομώνυμο αρχείο που είδαμε στην Server-side περίπτωση. Εδώ απουσιάζει το attribute runat="server" και επομένως το script κατεβαίνει στον browser. Προτού δούμε τον κώδικα του αρχείου menu.js, ας ρίξουμε μια ματιά στο φάκελο με τα αρχεία του παραδείγματος:


Εικόνα


Τα αρχεία hi-5.htm, kalomoira.htm και paparizou.htm είναι όλα παρόμοια αρχεία σαν το παραπάνω και διαφέρουν μόνο στον τίτλο και το <h2> tag. Και τώρα ας δούμε και τον JavaScript κώδικα του αρχείου menu.js:

Κώδικας: Επιλογή όλων

function disableCurrentLink&#40;&#41; &#123;
  var div = document.getElementById&#40;"menu"&#41;
  var links = div.getElementsByTagName&#40;"a"&#41;
  for &#40;var i = 0; i < links.length; i++&#41; &#123;
    var link = links&#91;i&#93;
    if &#40;link.href == location.href&#41; &#123;
      var text = document.createTextNode&#40;link.text&#41;
      link.parentNode.insertBefore&#40;text, link&#41;
      link.style.display = "none"
    &#125;
  &#125;
&#125;
Ο κώδικας είναι πιο σύντομος αλλά και πιο περίπλοκος. Δεν υπάρχει πάντως λόγος να τον καταλάβετε αν δε θέλετε. Ωστόσο θα κάνουμε μια προσπάθεια. Όπως είπαμε σκοπός της ρουτίνας disableCurrentLink() είναι να βρει το προβληματικό link, να το κρύψει και να προσθέσει λίγο κείμενο πριν από αυτό. Ξεκινάμε ψάχνοντας για το <div> με το id menu. Όπως βλέπετε έχω βάλει όλα τα links σε ένα <div>, γιατί δε θέλω να ψάξει ο κώδικας όλα τα links της σελίδας παρά μόνο αυτά που αποτελούν το μενού. Αυτό ακριβώς κάνουμε στη δεύτερη εντολή, όπου αποθηκεύουμε όλα αυτά τα links σε ένα Array με το όνομα links. Στη συνέχεια ακολουθεί ο βρόγχος που εξετάζει ένα-ένα τα links. Ο βασικός έλεγχος είναι ανάμεσα στην ιδιότητα href του link και την ομώνυμη ιδιότητα του location. Το αντικείμενο location περιέχει τη θέση - το URL - της τρέχουσας σελίδας. Αν λοιπόν οι δύο ιδιότητες έχουν ίδια τιμή σημαίνει ότι βρήκαμε ένα link που πρέπει να γίνει κείμενο.

Θα μπορούσαμε να ξεκινήσουμε κρύβοντας το link, αλλά θα το αφήσουμε για μετά. Έτσι ή αλλιώς είναι το ίδιο. Έτσι ξεκινάμε φτιάχνοντας το κείμενο που θα πάρει τη θέση του, με τη μέθοδο createTextNode του πανταχού παρώντος αντικειμένου document. Το κείμενο λαμβάνει την τιμή link.text όπως είναι φυσικό. Η επόμενη εντολή είναι ίσως η πιο δύσκολη. Θέλουμε να προσθέσουμε το κείμενο πριν το link αλλά δε μπορούμε να το κάνουμε απευθείας, πρέπει να βρούμε το γονέα που περιέχει το link. Στη συγκεκριμένη περίπτωση αυτός είναι το <div> και θα μπορούσαμε να χρησιμοποιήσουμε τη διαθέσιμη μεταβλητή div. Για λόγους ευελιξίας χρησιμοποίησα την ιδιότητα parentNode του link η οποία επιστρέφει το γονέα. Καλούμε μετά τη μέθοδο insertBefore() του γονέα που πραγματοποιεί την εισαγωγή. To text εισάγεται πριν το link. Τέλος κρύβουμε το link αλλάζοντας την τιμή της ιδιότητας display του style του.

Ίσως αναρωτηθήκατε γιατί κρύψαμε το link και δεν το αφαιρέσαμε μια και καλή. Δε διαθέτει σχετική μέθοδο το Document Object Model (DOM)? Φυσικά και διαθέτει, τη removeChild(). Ακόμα καλύτερα, διαθέτει τη μέθοδο replaceChild() που κάνει με μία κίνηση αυτό που εμείς κάναμε με δύο. Το πρόβλημα είναι ότι η διαγραφή ενός link επηρεάζει αυτόματα το Array links μειώνοντας τα στοιχεία του κατά ένα. Θα πρέπει επομένως να καλέσουμε μετά την εντολή i-- ώστε να αποφύγουμε να πηδήξουμε το επόμενο στοιχείο του Array που ξαφνικά έχει αλλάξει index. Δεν υπάρχει αληθινό πρόβλημα με αυτό, αλλά γενικά προτιμώ να αποφεύγω τέτοιες επιπλοκές όταν μπορώ. Τώρα που το ξανασκέφτομαι όμως είναι μάλλον απίθανο να υπάρχουν δύο αυτοαναφορικά links στο ίδιο μενού, οπότε θα μπορούσαμε αμέσως μετά την αντικατάσταση να διακόψουμε τη ρουτίνα με return.

Θα προσθέσω εδώ ότι η εκτέλεση της ρουτίνας disableCurrentLink(), που μόλις είδαμε, με την ολοκλήρωση του φορτώματος της σελίδας μπορεί να μην είναι η καλύτερη επιλογή. Αν φανταστούμε μία σελίδα με 50K HTML κώδικα καταλαβαίνουμε ότι τα links - που λογικά θα έχουν κατέβει και εμφανιστεί από τα πρώτα - θα είναι ορατά από το χρήστη για αρκετά δευτερόλεπτα, δίνοντάς του τη δυνατότητα να κάνει κλικ στο προβληματικό link. Επομένως η καλύτερη στιγμή να τρέξουμε το script είναι όσο γίνεται πιο γρήγορα, δηλαδή αμέσως μετά το κλείσιμο του tag <div>. Βγάλτε λοιπόν το χειριστή συμβάντος onLoad και γράψτε τον εξής κώδικα μετά το </div>:

Κώδικας: Επιλογή όλων

<script type="text/javascript">
  disableCurrentLink&#40;&#41;
</script>
Δε θα επαναλάβω εδώ τα συν και πλην των δύο μεθοδολογιών Server vs Client, καθώς μπορείτε να τα βρείτε στο τέλος του προαναφερθέντος άρθρου.
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Μενού με ένδειξη τρέχουσας σελίδας

Δημοσίευση από skeftomilos » 10 Απρ 2005 16:07

Τα links διαθέτουν ένα χαρακτηριστικό που μπορεί να κάνει τον κώδικα του αρχείου menu.js ακόμα απλούστερο. Οι browsers εμφανίζουν τα links με μορφή απλού κειμένου όταν δεν περιλαμβάνουν attribute href, για παράδειγμα <a>Καλομοίρα</a>. Μπορούμε να εκμεταλλευτούμε αυτό το χαρακτηριστικό προς όφελός μας. Ο παρακάτω κώδικας ...

Κώδικας: Επιλογή όλων

var text = document.createTextNode&#40;link.text&#41;
link.parentNode.insertBefore&#40;text, link&#41;
link.style.display = "none"
... μπορεί να αντικατασταθεί από τον ...

Κώδικας: Επιλογή όλων

link.removeAttribute&#40;"href"&#41;
Και οι δύο τεχνικές λειτουργούν το ίδιο καλά σε όλους τους Browsers (Firefox, IE, Opera).
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Απάντηση

Επιστροφή στο “JavaScript και Frameworks”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες