Logo JsDir.com [niente]
Bring Your Site To Life!!!
24 Luglio 2008 - 7:36:38 - 161 scripters on-line! - La tua posizione nel sito: StaffScripts/Script051/
BedInLecce
StaffScripts
Menu al lato destro

Autore: Riccardo Data: 03/09/2001 Downloads: 3179 Voto: 1/5 Download P r o v a


Menu al margine destro

Newsgroups: it.comp.lang.javascript
Date: Tue, 28 Aug 2001 10:57:01 +0000 (UTC)
Subject: [newbie] menu scorrevole laterale
From: "nico mattei" <neetcomAThotmail.com>

Salve, mi dite (please) come si fa un menų laterale a destra posizionato 
sempre alla stessa altezza (in pratica che scorre insieme alla pagina) e che 
magari possa contenere una tabella html giā pronta?
Grazie e perdonatemi l'incapacitā congenita.

06/12/2001
Grazie a Massimo Moretti per avermi suggerito una modifica che consente al menu di funzionare con le ultime versioni di Netscape 6


      Ancora una volta l'idea per uno script mi viene dal NewsGroup, e la richiesta che all'inizio sembrava semplice da soddisfare si è trasformata in un bell'esercizio di JavaScript perché ho trovato alcuni problemi che mi hanno fatto penare per essere risolti.
      Ovviamente la richiesta di Nico non può che soddisfarsi con un layer, ma il buon Explorer ha un brutto difetto: allarga le sue barre di scorrimento per adattarsi alla larghezza "effettiva" della pagina. Ciò vuol dire che se noi abbiamo un layer largo ad esempio 200 pixel e lo posizioniamo 50 px a sinistra del margine destro della pagina per nascondere i rimanenti 150, lui allarga la barra orizzontale, così uno deve semplicemente scrollare in orizzontale per vedere quel che noi abbiamo nascosto. Per contro Netscape quando ci restituisce (con window.innerWidth) la larghezza della pagina, non tiene conto della larghezza della barra di scorrimento (16 pixel) ed ho dovuto ovviare modificando le variabili di posizionamento. A questo si aggiungono i soliti problemi di compatibilità per il DHTML dei vari browser.
      Comunque cominciamo subito con il metodo di utilizzo, nella descrizione dello script vi farò vedere per grandi linee un oggetto del Core di JavaScript (Function per il quale seguirà un tutorial) che ho usato per la prima volta in questo script e che può essere molto utile proprio per la gestione della sintassi richiesta dai vari browser nel trattare i livelli.

      Il menu si compone di due livelli: MenuKey che contiene l'immagine da cliccare per visualizzare il menu, e MenuBody che contiene il menu vero e proprio: la "tabella HTML già pronta" che chiedeva Nico.
      Innanzitutto cominciamo dalla scelta del modo di attivazione del menu: ho preferito far cliccare sull'immagine piuttosto che usare onMouseOVer ancora una volta per correggere un problema di IE. Infatti se usiamo onMouseOver su un DIV che contiene degli HREF, quando il mouse è su uno dei links per il livello scatta l'event-handler onMouseOut (che ovviamente avevo collegato alla funzione che nasconde il menu), con la conseguenza che il menu veniva appunto nascosto. Ho dovuto dunque usare due livelli distinti (per compensare il problema della scrollbar) ed il click sull'immagine per compensare il problema dell'onMouseOver/Out.
      Il menu si presenta, grosso modo, come il codice che segue, dal quale, per ragioni d'impaginazione, ho tolto vari tag:
<DIV ID="MenuKey" STYLE="position:absolute;visibility:hidden;top:1;left:1; [...
   ...] width:20;layer-background-color:#ffffff;background:#ffffff">
<A HREF="javascript:ShowMenu()"><IMG SRC="menu.gif" WIDTH="20" HEIGHT="100" BORDER="0"></A>
</DIV>

<DIV ID="MenuBody" STYLE="position:absolute;visibility:hidden;top:1;left:1; [...
   ...] width:40;layer-background-color:#ffff00;background:#ffff00">
	<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0">
		<TR><TD><B><A HREF="#">Voce 0</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 1</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 2</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 3</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 4</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 5</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 6</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 7</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 8</A></B></TD></TR>
		<TR><TD><B><A HREF="#">Voce 9</A></B></TD></TR>
	</TABLE>
</DIV>
      Come si vede, tutti e due i livelli sono all'inizio invisibili e posizionati nell'angolo superiore sinistro del browser. Ho previsto un background per colorarli, ma se li volete trasparenti basterà togliere layer-background-color (per NN) e background (per IE).
      Notate inoltre che sarà importante definire i tre attributi width presenti, quelli degli stili dei livelli e dell'immagine. Nel caso di MenuKey il "width" del livello deve corrispondere alla larghezza dell'immagine, nel caso di MenuBody dovrete settarne la larghezza perché contenga la tabella. Queste larghezze sono importanti per IE, come ormai avrete intuito, per il problema delle barre di scorrimento, e tutti e tre dovrete impostarli "a mano", perché se omettete il width IE assumerà delle larghezze arbitrarie.
      Nel MenuKey potrete ovviamente cambiare l'immagine, ma attenzione al tag HREF che contiene la chiamata alla funzione di visualizzazione del menu. La tabella in MenuBody è invece puro e semplice codice HTML, quindi potete spaziare con la fantasia: link testuali (come ho fatto io), mappe o immagini cliccabili, eventualmente altri menu dinamici (ma tenete conto che probabilmente dovrete agire sul codice che li gestisce perché i livelli dei menu che andrete a mettere qui dentro saranno contenuti nel MenuBody quindi dovrete sicuramente modificare il percorso di ricerca degli oggetti).
      Prima dello script ricordate che dovrete modificare il BODY del vostro documento aggiungendo due event-handler:
<BODY ...  onLoad="Init()" onResize="self.location.reload()">
      Il primo serve a far partire lo script quando i documento è caricato, il secondo serve per consentire a Netscape di riposizionare correttamente i livelli nel caso la finestra del browser venga ridimensionata. Purtroppo Opera sembra indifferente ad onResize, quindi questa sarà l'unica incompatibilità (che ho trovato) per questo menu che rimane, per il resto, perfettamente funzionante.

      E veniamo allo script, ve lo spiattello subito tutto, ma non vi spaventate, specialmente per le parti che ho colorato in rosso! :-)
<SCRIPT>
<!--
// --------------- Personalizzazioni ----------
var MenuWidth=40; // Larghezza del MenuBody
var MenuLeft=20; // Larghezza del MenuKey
var MenuTopMargin=20; // Distanza voluta dal margine superiore del browser (o del Frame)
// -------------  Fine Personalizzazioni --------

var nn=document.layers?true:false;
var NN6=navigator.userAgent.toLowerCase().indexOf("netscape6")!=-1;
var OPERA=navigator.userAgent.toLowerCase().indexOf("opera")!=-1;
var Dom2=document.getElementById&&(NN6||OPERA)?true:false;
var MenuKeyLayer=null,MenuBodyLayer=null,stato=false,Sinistra,Destra,CorreggiNN=0;

function Init()
  {
  if (NN6||nn&&window.innerWidth-document.width==0)
    {MenuLeft+=16;
    MenuWidth+=16;
    CorreggiNN=16;}

  MenuKeyLayer=nn?document.layers.MenuKey: [...
       ...] Dom2?document.getElementById("MenuKey"):document.all.MenuKey;
  MenuBodyLayer=nn?document.layers.MenuBody: [...
       ...] Dom2?document.getElementById("MenuBody"):document.all.MenuBody;
  Sinistra=nn||Dom2?window.innerWidth-MenuWidth-MenuLeft+CorreggiNN: [...
       ...] document.body.clientWidth-MenuWidth-MenuLeft;
  Destra=nn||Dom2?window.innerWidth-MenuLeft:document.body.clientWidth-MenuLeft;
  
  if (nn)	{
    MenuKeyLayer.left=window.innerWidth-MenuLeft;
    MenuBodyLayer.left=window.innerWidth-MenuWidth;}
    else if (Dom2){
      MenuKeyLayer.style.left=window.innerWidth-MenuLeft;
      MenuBodyLayer.style.left=window.innerWidth-MenuWidth;}
      else{
      MenuKeyLayer.style.left=document.body.clientWidth-MenuLeft;
      MenuBodyLayer.style.left=document.body.clientWidth-MenuWidth;}

  nn?MenuKeyLayer.visibility="visible":MenuKeyLayer.style.visibility="visible";

  Nascondi = new Function (nn?"MenuKeyLayer.left=Destra;MenuBodyLayer.visibility='hide'": [...
       ...] "MenuKeyLayer.style.left=Destra;MenuBodyLayer.style.visibility='hidden'");

  Mostra = new Function (nn?"MenuKeyLayer.left=Sinistra;MenuBodyLayer.visibility='show'": [...
       ...] "MenuKeyLayer.style.left=Sinistra;MenuBodyLayer.style.visibility='visible'");

  Riposiziona = new Function (nn?"Pos=window.pageYOffset+MenuTopMargin;MenuKeyLayer.top=Pos; [...
       ...] MenuBodyLayer.top=Pos":Dom2?"Pos=window.pageYOffset+MenuTopMargin; [...
       ...] MenuKeyLayer.style.top=Pos;MenuBodyLayer.style.top=Pos":"Pos=document.body.scrollTop [...
       ...] +MenuTopMargin;MenuKeyLayer.style.top=Pos;MenuBodyLayer.style.top=Pos")

  timer1=setInterval("Riposiziona()",25);
  }

function ShowMenu(){
  stato=!stato;
  stato?Mostra():Nascondi();}

//-->
</SCRIPT>
      Prima di continuare vi spiego come funziona lo script così da darvi un quadro d'insieme.
      Quando la pagina viene caricata i due livelli sono invisibili e posizionati all'angolo superiore sinistro (coordinate 1,1). La funzione Init() provvede, come vedremo fra poco, a posizionare i livelli a destra, spostati dal margine quanto basta perché siano visibili nella pagina, quindi a sinistra, rispetto al margine destro, tanto quanto è il valore di MenuLeft e MenuWidth. In pratica si accavallano, ma mentre il livello del menu (MenuBody) resta invisibile, l'altro (MenuKey) viene visualizzato e può essere cliccato. Quando clicchiamo sull'immagine, il MenuBody viene reso visibile, ed il MenuKey viene spostato a sinistra di quanto basta per accostarsi al margine sinistro del MenuBody. Al successivo click, l'operazione si inverte: MenuBody ridiventa invisibile e MenuKey ritorna a destra.
      Sempre da Init() viene generata una funzione (simile a quella già vista nello script Marquee) che ogni 25 millisecondi riposiziona il menu secondo il valore di MenuTopMargin.

      Le prime tre righe dello script consentono la personalizzazione:
- MenuWidth: è la larghezza della tabella, quindi assume lo stesso valore per del "width" nello STYLE di MenuBody
- MenuLeft: analogamente a MenuWidth è la larghezza del livello che contiene l'immagine: MenuKey
- MenuTopMargin: è la distanza che volete assuma il menu rispetto al margine superiore della finestra (o del frame).

      Seguono quattro assegnazioni di variabili che trovate spesso quando si usano i livelli, niente su cui valga la pena di soffermarsi, tranne che sono fatte ad hoc per questo script che deve gestire poche proprietà (posizione e visibilità), quindi difficilmente riutilizzabili, specialmente la Dom2. Notate che qui il DOM2 viene usato solo per Opera e Netscape 6, mentre IE (in tutte le versioni) viene trattato come DOM1, quindi usando la collection "document.all".
      Nella riga successiva valorizzo alcune variabili globali e poi inizia la funzione Init(), triggerata dall'onLoad del BODY, che come vedrete tra poco fa ben altro che inizializzare qualche variabile.
      La prima istruzione corregge i valori di MenuLeft e MenuWidth (impostati nella sezione di personalizzazione) per compensare il difetto di Netscape (ricordate? non tiene conto della scrollbar nella larghezza del documento) e viene settata un'ulteriore variabile ("CorreggiNN") che ci servirà per spostare il livello con il tasto ("MenuKeyLayer").

      Nelle due righe successive vengono assegnati a MenuKeyLayer e MenuBodyLayer gli oggetti "livello" rispettando la sintassi dei vari browser.
      Le altre due righe assegnano alle variabili "Sinistra" e "Destra" due valori di posizione che vengono usati solo per il MenuKeyLayer. "Sinistra" contiene la posizione del livello per il menu aperto, "Destra" la posizione opposta.
      La if () successiva sposta i due livelli (che sono ancora invisibili e alla posizione inziale) al margine destro usando rispettivamente la sintassi richiesta da Netscape 4, Netscape 6 e Opera, e le varie versioni di IE.
      La riga successiva rende visibile il MenuKey, cioè il tasto che cliccato visualizzerà il menu.
      Salto a piè pari, ma ci ritorno subito, le tre righe successive, per concludere la funzione Init(). Viene fatto partire un timer (con setInterval) che richiama ciclicamente la funzione di riposizionamento (è l'ultima delle righe "rosse").
      La funzione successiva (ShowMenu()) si attiva al click sull'immagine. La variabile stato era stata dichiarata nell'ultima riga di var all'inizio dello script, e settata a false. Quando la funzione viene eseguita cambia il valore della variabile (da false passa a true e viceversa) che viene usata per far scattare una delle due funzioni Mostra() o Nascondi() che si occuperanno di rendere visibile o invisibile il menu.

      "Riposiziona()", "Mostra()" e "Nascondi()" sono le tre righe colorate che abbiamo saltato fino adesso, il modo in cui le ho implementate è una novità per me e credo anche per molti di voi. Per il momento lo vediamo velocemente, appena ne avrò capito abbastanza :-) ne farò un tutorial.
      Ne analizziamo una sola (Mostra), le altre due sono simili.
      La funzione ShowMenu() chiama una funzione secondo il valore della variabile "stato", ad esempio la funzione Mostra() dovrebbe, nel nostro caso, spostare a sinistra il layer MenuKey e rendere visibile MenuBody. Per accontentare il DOM dei vari browser avremmo bisogno di una funzione di questo tipo:
   (1)   function Mostra()
            {
            if (nn)
               {
               MenuKeyLayer.left=Sinistra;
               MenuBodyLayer.visibility='show';
               }
            else
               {
               MenuKeyLayer.style.left=Destra;
               MenuBodyLayer.style.visibility='visible';
               }
            }
      Sottolineo che sto facendo distinzione solo fra Netscape4 e gli altri browser/DOMs perché per questi ultimi, nel nostro caso, la sintassi è identica per tutti.
      Quel che succede durante l'esecuzione dello script è che ogni volta che la funzione viene invocata verifica una condizione (if () {} else {} ) ed esegue il codice appropriato. Nel caso di questa funzione (Mostra()) il danno (tempo di esecuzione della funzione) è poco, perché la funzione lavora pochissimo dato che si attiva solo se noi clicchiamo sul link, ma l'altra funzione (Riposiziona()) deve lavorare 40 volte al secondo (setInterval() è impostato a 25 millisecondi) quindi se il nostro visitatore resta sulla pagina 5 minuti viene eseguita (ed esegue 3 "if" e 3 istruzioni per volta) la bellezza di 144.000 volte! Il rischio è che il browser vada in crash, specialmente se deve eseguire anche altri script.
      Sarebbe bello poter avere nel sorgente SOLO la funzione per Netscape4, o solo quella per Explorer, o per Opera, o per Netscape 6, eliminando la necessità di eseguire tutti quegli if ().
      Ci viene in aiuto l'istruzione Function (attenzione: "Function" con la "F" maiuscola!!!) che è un'istruzione del Core di JavaScript ed è un "costruttore".
      L'uso è immediato, con la stessa semplicità con cui si dichiara e valorizza una stringa:
pippo = "Amico di Topolino";
      così si dichiara una nuova funzione:
Avviso = new Function("alert(pippo)");
      Quando viene eseguito "new Function()" l'argomento fra virgolette viene compilato dall'interprete JavaScript del browser e noi avremo disponibile una nuova funzione. Copiate ed incollate in un editor questo script per fare una semplice prova:
<SCRIPT>
<--
var pippo = "Amico di Topolino";
Avviso = new Function("alert(pippo)");	
Avviso();	
//-->
</SCRIPT>
      Come vedete viene dichiarata una variabile, e successivamente una funzione (Avviso) che usa la variabile. lanciata la variabile viene eseguito l'alert(). Notate che quando dichiaro la nuova funzione ometto le parentesi tonde.

      Come ho usato questo costruttore nello script?
      Semplicemente dichiarando la funzione (Mostra) ed assegnando come argomento di Function() una stringa diversa a seconda che la variabile nn sia true o False.
      Quel che ottengo è che nello script non avremo la funzione (1) bensì la funzione:
function Mostra()
  {
  MenuKeyLayer.left=Sinistra;
  MenuBodyLayer.visibility='show';
  }
      se il browser è Netscape 4.x, oppure la funzione
 function Mostra()
  {
  MenuKeyLayer.style.left=Destra;
  MenuBodyLayer.style.visibility='visible';
  }
      se il browser è uno qualsiasi degli altri. Per funzionare il nostro script dovrà solo eseguire una di queste due funzioni (non ne esistono altre, il costruttore una volta usato finisce li come la funzione Init() che lo contiene).
      Ci sono due svantaggi nell'uso di Function:
      Il primo è che bisogna stare molto attenti agli apici sincoli e doppi che possono generare gli stessi problemi di quando li usiamo per le stringe: è per questo che ho assimilato (idealmente) l'uso di Function() all'uso delle stringhe, il secondo è che la funzione viene generata ogni volta che il costruttore viene richiamato e dato che il costruttore non è molto performante, in usi più complessi potremmo ottenerne un decadimento di prestazioni piuttosto che un incremento.

Riccardo      





Per navigare correttamente il sito è necessario abilitare i cookies.
Enjoy Open Source!
ffx80wh2

    javascript
 
 
 
         Stampa
          Segnala
          Preferiti





thb1202