+ Rispondi al messaggio
Visualizzazione dei risultati da 1 a 5 su 5

nav con creazione tags tramite JS e eventi mouse

  1. #1
    BennyB non è in linea Scolaretto
    Salve.
    Ho provato a realizzare una routine JS che crea un sotto menu in una struttura al passaggio del mouse su un tag UL. E' un esempio di studio che lavora sulle classi. L'idea è quella di non utilizzare il solito sistema aggiungendo una classe 'active' (che poi diventa 'hidden') al sotto menu.
    Probabilmente non è fattibile, non so. O meglio: così non funziona. questa la struttura HTML:
    codice HTML:
    <div class="nav cn">
      <ul>
        <li class="item">
          <a href="#">Home</a>
        </li>
        <li class="item">
          <a href="#">Dato selezionato</a>
        </li>
        <li class="item">
          <a href="#">Dato 3</a>
        </li>
      </ul>
    </div>
    Questa la formattazione CSS (solo il necessario):
    codice HTML:
    .cn {
      margin-left: auto;
      margin-right: auto;
    }
    .nav > ul {
      list-style: none;
      margin:0;
    }
    .item {
      display: inline-block;
      position: relative;
      list-style: none;
      padding-right: 20px;
      height: 65px;
    }
    .item a {
      line-height: 65px;
      text-decoration: none;
      font-family: cursive;
      font-size: 25px;
      color: white;
    }
    .item a:hover {
      background-color: rgb(220, 223, 52)
    }
    .sub {
      position: absolute;
      top:105%;
      left: 0;
      border: 2px solid darkgrey;
      border-radius: 10px;
      width: 300px;
      z-index: 5;
    }
    .sub > li {
      display: block;
      padding: 15px 5px;
      background-color: white;
      border: 1px solid lightgrey;
      color: black;
      top: 85px;
      z-index: 1
    }
    .sub > li:hover {
      background-color: #e4e773;
    }
    Infine, questa la routine JS:
    var elements = document.getElementsByClassName("item");
    var subElements = document.getElementsByClassName("sub");
    
    for(var i = 0; i < elements.length; i++) {
      (function(index) {
        elements[index].addEventListener("mouseover", function() {
           // alert("Clicked index: " + index);
        if (!this.getElementsByClassName("sub").length > 0) {
            switch(index){
              case 0:
              break;
              case 1:
              let arrLi = ['Dato sub 1', 'Dato sub 2', 'dato sub 3'];
              var newUL =document.createElement('UL');
              newUL.className = 'sub';
              for (var i = 0; i < arrLi.length; i++){
                var newLi = document.createElement('li');
                newLi.innerHTML = arrLi[i];
                newUL.appendChild(newLi);
              }
              this.appendChild(newUL);
              elements[index].getElementsByClassName("sub")[0].addEventListener("mouseleave", function(){
                elements[index].getElementsByClassName("sub")[0].remove;
              });
              break;
              default:
            };
          };
        });
      })(i);
    }
    
    Quando passo sull'item 2 con il mouse, il menu si crea, e riesco ad accederci.
    Il problema è nel chiuderlo uscendo dal sotto menu. Evidentemente la seconda assegnazione 'mouseleave' non è corretta.
    Qualcuno sa spiegarmi dove sbaglio?

  2. #2
    L'avatar di _alka_
    _alka_ non è in linea Very Important Person
    Quote Originariamente inviato da BennyB Visualizza il messaggio
    Qualcuno sa spiegarmi dove sbaglio?
    Ci sono una infinita di errori, alcuni concreti, altri di sintassi, altri ancora di forma.

    Mi spiego. Innanzitutto, la leggibilità del codice è molto bassa: non so se è un problema di formattazione, ma vedo il ripetersi di espressioni con accesso ad array che potrebbero essere semplificate assegnando il riferimento a una variabile e usando quello.

    C'è poi una commistione nell'uso di var, in alcuni casi, e di let in altri. Perché non usare sempre let?

    Non è chiaro poi qual è il senso di creare la funzione anonima con parametro index per passargli direttamente il valore nel ciclo usando la variabile "i" ed eseguirla subito: complica solo il codice (che già è poco leggibile) e, in questo contesto, non fornisce peraltro alcuna utilità di sorta, nella forma o nelle performance o in altri aspetti.

    Tra le altre cose notate, nell'evento mouseleave sarebbe più opportuno che tu ti riferissi all'elemento da eliminare usando il parametro event (che riporta nella proprietà target la voce di menu che tu vorresti rimuovere dal DOM); ad esempio:
    elements[index].getElementsByClassName("sub")[0].addEventListener("mouseleave", function(event) {
        event.target.remove();
    });
    
    Inoltre, nel codice hai scritto anche la funzione remove() senza mettere le parentesi in fondo: in questo modo, stai facendo riferimento alla "funzione remove" in quanto oggetto o valore, senza assegnarlo da nessuna parte, e quindi il tuo codice rimane inerte.

    Non potendo testare il codice in diretta, non so se gli esempi che ho fornito sono validi nel tuo contesto ma le spiegazioni dovrebbero essere chiare.

    Per il resto, secondo me dovresti fare molto ordine ed essere più rigoroso nella scrittura del codice: già è un requisito fondamentale per poterlo leggere non la settimana dopo ma il giorno dopo, e in JavaScript diventa ancora più rilevante trattandosi di un linguaggio di scripting con molte particolarità (riferirsi a una funzione in altri linguaggi senza invocarla e senza assegnarla avrebbe generato un errore di compilazione, ad esempio).

    In merito all'implementazione, sicuramente non è efficace: se si usano i fogli di stile o strutture del DOM fisse che vengono visualizzate e nascoste, un motivo c'è. Se stai facendo tutto questo come esercizio, potrebbe andare bene ma il mio suggerimento è quello di esercitarti usando certi strumenti (es. funzione anonima con invocazione immediata) nel contesto in cui essi sono realmente utili, altrimenti generano più confusione che chiarezza.

    Questi sono solo ovviamente pareri personali.

    Ciao!
    ℹ️ Leggi di più su _alka_ ...

  3. #3
    BennyB non è in linea Scolaretto
    Grazie della spiegazione e dei consigli. Studiare da solo senza avere qualcuno che corregge e motiva le correzioni è complicato.
    Ho svolto le modifiche al codice, e forse ora va un po' meglio. Se hai la pazienza di commentare, mi piacerebbe una valutazione su quanto fatto.
    Vengo al punto.

    L'errore principale constava in effetti della mancanza delle parentesi dopo in remove. Disattenzione puerile, dovuta all'inesperienza.

    Il progetto, comunque ha l'obiettivo di:
    • capire come assegnare eventi a tags raccolti con riferimento alla class.
    • Esercitarmi sulla manipolazione DOM
    • Lavorare con Switch

    Inoltre, utilizzare momentaneamente arrays per poi sostituirli con oggetti JSON (come vedi non ho inserito attributi href perché pensavo di importarli insieme alle parti testuali tramite una promise o una callback).
    Il progettino mi serve per capire come attraversare il DOM e metterci le mani. Chiaro che queste sono operazioni elementari...

    Questo il codice modificato:
    var elements = document.getElementsByClassName("item");
    var subElements = document.getElementsByClassName("sub");
    var arrLi1 = ['Dato 1 sub 1', 'Dato 2 sub 1', 'dato 3 sub 1'];
    var arrLi2 = ['Dato 1 sub 2', 'Dato 2 sub 2', 'dato 3 sub 2',, 'dato 4 sub 2'];
    
    let creaLi = function(itemClass, arr){
      let newUL =document.createElement('UL');
      newUL.className = 'sub';
      for (let i = 0; i < arr.length; i++){
        let newLi = document.createElement('li');
        newLi.innerHTML = arr[i];
        newUL.appendChild(newLi);
        itemClass.appendChild(newUL);
        itemClass.getElementsByClassName("sub")[0].addEventListener("mouseleave", function(event){
          event.target.remove();
        });
      };
    };
    
    let creaSub = function(index) {
      elements[index].addEventListener("mouseover", function() {
         // alert("Clicked index: " + index);
      if (!this.getElementsByClassName("sub").length > 0) {
          switch(index){
            case 0: //link a Home
              break;
            case 1:
              creaLi(this, arrLi1);
              break;
            case 2:
              creaLi(this, arrLi2);
              break;
            default:
            }
          };
        });
      };
    
    for(let i = 0; i < elements.length; i++) {
      creaSub(i);
    };
    
    Una considerazione sul fatto di popolare menu e sotto menu con elementi esterni: si usa JSON di solito, oppure ci sono altre tecniche? Poi, immagino che si manipoli la visualizzazione tramite CSS. Giusto?

  4. #4
    L'avatar di _alka_
    _alka_ non è in linea Very Important Person
    Quote Originariamente inviato da BennyB Visualizza il messaggio
    Ho svolto le modifiche al codice, e forse ora va un po' meglio.
    Decisamente ora il codice è molto più leggibile.

    Quote Originariamente inviato da BennyB Visualizza il messaggio
    L'errore principale constava in effetti della mancanza delle parentesi dopo in remove.
    Immaginavo, anche se rifattorizzare il codice restante è stata comunque una buona idea.

    Quote Originariamente inviato da BennyB Visualizza il messaggio
    Disattenzione puerile, dovuta all'inesperienza.
    Non sai quante volte capiterà ancora, anche con l'inesperienza, ma è il bello (o il brutto) di lavorare con JavaScript in questo caso.

    Quote Originariamente inviato da BennyB Visualizza il messaggio
    Una considerazione sul fatto di popolare menu e sotto menu con elementi esterni: si usa JSON di solito, oppure ci sono altre tecniche?
    Non mi è chiaro cosa intendi. JSON è un formato di dati, che coincide "incidentalmente" (in senso ironico) con la sintassi che si usa per definire un oggetto in JavaScript.

    Detto questo quindi, in JavaScript tu fai uso di array oppure di valori primitivi oppure ancora di oggetti, se parliamo di sintassi e dichiarazione di variabili con assegnazione di valori.

    JSON è una stringa, un formato di rappresentazione, un qualcosa che si trasferisce per poter essere "parsata" e trasformata in oggetto, o viceversa è l'oggetto a trasformarsi in stringa per poter essere trasferito (es. da o verso un server, o su file, ecc.).

    Quote Originariamente inviato da BennyB Visualizza il messaggio
    Poi, immagino che si manipoli la visualizzazione tramite CSS. Giusto?
    In genere è consigliato in quanto si scrive meno codice JavaScript, ci si accontenta di assegnare la giusta classe CSS al menu o all'elemento del DOM interessato, si evita di modificare proprietà multiple dell'elemento del DOM incidendo negativamente sulle performance della pagina.

    Ciao!
    ℹ️ Leggi di più su _alka_ ...

  5. #5
    BennyB non è in linea Scolaretto
    Ti ringrazio ancora per la risposta.
    Come detto, ora la mia routine funziona, ma resta un piccolo problema.
    Allora, l'evento mouseleave viene correttamente intercettato se esco dalla UL del sotto menu. Però, se passo con il pointer del mouse ancora sul primo tag UL (classe primary) e non sul sotto menu che si crea, questo rimane dov'è finché non ci torno con il mouse (e poi esco nuovamente).
    Quello che vorrei fare e inserire nella function creaSub un temporizzatore che dopo 2 secondi controlla se il pointer del mouse è ancora nella UL del sotto menu (nel caso deve far ripartire il conteggio), altrimenti la rimuove.
    Ho pasticciato un po' con setTimeout(), ma non riesco a capire come collegare l'evento al temine della temporizzazione.
    Avresti la pazienza di suggerirmi almeno come muovermi?

    Riguardo alla soluzione da me applicata, ho visto che Bootstrap applica varie routine JS (o JQuery) per animare i menu.
    Qui https://diffa.org, per esempio, nel nav utilizza il passaggio da display: none a display: block e incrementa temporizzando l'altezza da 0 al valore voluto per visualizzare il sotto menu; pare che con i CSS formatti solo l'elemento, e la visualizzazione e l'automazione sembrano svolte tramite codice. Il codice in questione, non l'ho trovato (ma, da neofita non so bene dove cercare). Credo sia una routine Bootstrap. In ogni modo, agisce diversamente da quello che io faccio, ma neppure tanto. Mi piacerebbe poter accedere alla parte di codice interessata (sempre per studio personale, va da sé)... se hai tempo di darci un'occhiata, altrimenti pazienza, attenderò di saperne di più.
    Grazie.

+ Rispondi al messaggio

Potrebbero interessarti anche ...

  1. Risolto: [VB2010] Modificare opacità form con eventi mouse
    Da imbranato nel forum Visual Basic .Net
    Risposte: 2
    Ultimo Post: 05-05-2012, 17:30
  2. Help eventi mouse VB2008
    Da devildragon nel forum Visual Basic .Net
    Risposte: 2
    Ultimo Post: 27-03-2009, 00:50
  3. API intercettare eventi del mouse
    Da bisius nel forum Visual Basic 6
    Risposte: 1
    Ultimo Post: 18-08-2007, 16:47
  4. eventi mouse javascript
    Da thefoxwhite nel forum HTML, CSS e JavaScript
    Risposte: 1
    Ultimo Post: 27-12-2005, 13:24
  5. Articolo: Reagire agli eventi generati dal mouse
    Da freezer nel forum Visual Basic 6
    Risposte: 0
    Ultimo Post: 18-11-2005, 10:47