Linuchs: Bearbeitung des Wiki: Playlist

Moin,

ich möchte zum Thema Playlists etwas bei- und eintragen.

Da ein Playlist-Modul in der Regel in eine Webseite eingefügt wird, müssen die Javascript-Variablen innerhalb des Moduls bleiben und nicht gleichnamige Variablen der übrigen Webseite verfälschen.

Wie funktioniert das?

Gruß, Linuchs

  1. Hallo Linuchs,

    https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/OOP/Module_und_Kapselung

    Wenn Du kein API herausgeben musst, reicht das Einbetten in eine IIFE.

    Wir helfen Dir aber auch gern. Du kannst in deinem User Namespace des Wiki anfangen und dann überarbeiten wir das gemeinsam.

    Wäre dein Wiki-Benutzername Linuchs, würdest Du dafür z.B. die URL

    https://wiki.selfhtml.org/wiki/Benutzer:Linuchs/Playlists

    verwenden können. Nachher verschiebt man das Ergebnis an eine geeignete Stelle.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      das mit der Kapselung habe ich verstanden. Merkwürdig, dass man innerhalb der Kapsel immer den Kapselnamen voranstellen muss. Wenn ich mich recht entsinne zu Ur- und Cobolzeiten gab es sowas ähnliches wie

      with kapselname {
        ...
      }
      

      Chöre und Orchester stellen mehrere CDs vor mit Hörproben. Innerhalb der Kapsel plA (playlist A von mehreren) muss ich immer plA voranstellen. Und dann braucht man für jede PLaylist wieder so ein Konstrukt?

      var plA = {
         obj_audio  : document.getElementById("plA").getElementsByTagName("audio")[0] 
      ...
        // einen bestimmten Titel 0..n laden und starten
        ,playThis : function (ndx) {
          alert( "ndx=[" +ndx +"]" );
          plA.obj_audio.src = plA.arr_li[ndx].dataset.url;
      //  plA.arr_li[ndx].style.fontWeight = "bold";
          plA.obj_audio.play();
        }
      }
      

      Ich probiere es mal mit mehrdimensionalen Arrays

      <div class=playlist>
        <audio ...>
        <ul>
          <li data-src="hymne_eu.mp3">Eurohymne</li>
          <li data-src="hymne_d.mp3">Deutschlandhymne</li>
        </ul>
      </div>
      
      <div class=playlist>
        <audio ...>
      </div>
      
      <div class=playlist>
        <audio ...>
      </div>
      
      var arr_playlists = document.getElementsByClassName("playlist");
      for ( let i=0; i<arr_playlists.length; i++ ) {
        var arr_li  = arr_playlists[i].getElementsByClassName("li");
        console.log( "playlist[" +i +"] [" +arr_li.length +"] li erkannt" );
      ...
      }
      

      Möchte arr_li als zweite Dimension in arr_playlists einhängen, aaaber ...

      playlist[0] [0] li erkannt
      playlist[1] [0] li erkannt
      playlist[2] [0] li erkannt
      

      Wieso werden die li-Elemente nicht erkannt?

      Edit: ES MUSS TagName heißen

      1. Hallo Linuchs,

        wenn Du mit dem revealing module Pattern arbeitest, stellst Du im Prinzip ein Objekt bereit, dessen Implementierung auf Interna des Moduls zugreifen kann. Diese Interna sind letztlich in der Closure gespeichert, die zu dem Funktionskontext gehört, der das Objekt erzeugt hat, und damit gut versteckt.

        Dieses Objekt kann ein normales Objekt mit Methoden sein. Oder auch eine Funktion - siehe dazu weiter unten.

        Wenn Du Methoden dieses Objekts verwenden willst, musst Du natürlich immer obj.method() schreiben. Ist lästig, aber:

        Vergiss with

        Douglas Crockford teilt JavaScript im Schmetterlingsbuch (JavaScript: The Good Parts) in 3 Teile: Awful, Bad und Good. with ist bad. Der Grund:

        with (obj)
        {
           a = b;
        }
        

        lässt sich je nach Definiertheit von obj, obj.a und obj.b als eins von 4 Statements deuten:

        a = b;
        a = obj.b;
        obj.a = b;
        obj.a = obj.b;
        

        JS weiß erst, wenn es an dieser Stelle angekommen ist und getestet hat, ob obj, obj.a oder obj.b undefined sind, was es zu tun hat. Und das ist die Hölle für jeden Optimizer. Der strict mode verbietet es deshalb. Die Bequemlichkeit und Reduktion in Scriptgröße, die with mitbringt, rechtfertigt den negativen Einfluss auf die Eindeutigkeit der Ausführung nicht.

        var plA = { ... }
        

        Kann man machen, aber innerhalb von playThis solltest Du this statt plA verwenden. Dann KÖNNTEST Du die playThis-Funktion in einer Variablen ablegen und jedem plA Objekt als playThis zuweisen.

        Wieso werden die li-Elemente nicht erkannt?

        Weil li kein Klassenname ist und Du getElementsByClassName verwendest.

        Aber wie wär's hiermit - revealing module, das eine Funktion bereitstellt:

        function getNextSongPlayer(id) {
           const playList = document.getElementById(id);
           const obj_audio = playList.querySelector("audio");
           const songs = playList.querySelector("li");
        
           return function(ndx) {
              obj_audio.src = songs[ndx].dataset.url;
              arr_li[ndx].style.fontWeight = "bold";
              return obj_audio.play();
           }
        }
        
        playA = getNextSongPlayer("plA");
        playB = getNextSongPlayer("plB");
        
        playA(0);  // Spiele erstes Lied in Playlist A
        playB(0);  // Spiele erstes Lied in Playlist B
        

        Die Funktion, die aus getNextSongPlayer herauskommt, gibt das Promise zurück, das von play() geliefert wird. Du kannst also auf den Rückgabewert von playA oder playB mit .then und .catch reagieren, oder - in einer async-Funktion - mit await darauf warten.

        Diese Technik setzt auf Closures - wie das funktioniert, steht z.B. hier

        Rolf

        --
        sumpsi - posui - obstruxi