JavaScript/Tutorials/mobile Web-App mit HTML5

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Neben dem freien Internet haben native Apps einen festen Platz gefunden. Sie gelten als schnell, da sie in der nativen Programmiersprache des jeweiligen Betriebssystems geschrieben wurden. Andererseits ist man an dieses System gebunden, da man sie nur schwer auf andere Plattformen portieren kann und von den App-Stores der jeweiligen Plattformen abhängig ist. Dazu haben Untersuchungen ergeben, dass auf dem Weg vom App-Store über den Download zum Starten der App über 20% der potentiellen Nutzer verloren gehen.[1]

Progressive mobile Web-Apps werden nicht fest installiert, sondern werden wie eine normale Webseite unter einer festen URL vom Browser ausgeführt. So können sie problemlos auf allen mobilen Plattformen genutzt werden. Während früher das Fehlen nativer Features wie Nutzung von Kamera, Geolocation oder das Abfragen des Batteriestatus bemängelt wurde, entwickelt die Device and Sensors Working Group des W3C viele neue JavaScript-APIs, die den Nutzen mobiler Web-Apps progressiv verbessern können.

In diesem Artikel lernen Sie, wie Sie eine mobile Web-App mit HTML5 erstellen, die auf allen Plattformen läuft.

Vorüberlegungen[Bearbeiten]

Klassische Webseiten sind typischerweise einzelne HTML-Dokumente, die untereinander verlinkt sind. Beim Surfen mit mobilen Geräten außerhalb von WLAN-Hotspots sind diese Seiten oft sehr langsam, da sich geringe Datenübertragungsraten und besonders längere Antwortzeiten [2] oft deutlich auswirken. Während die Latenzzeit an der Leitung sonst ca. 25 Millisekunden beträgt, kann sie bei schlechtem Netzempfang selbst bei LTE bis zu 500 Millisekunden betragen.

Deshalb versuchen Apps die Inhalte in möglichst wenigen einzelnen Dokumenten zusammenzufassen. Diese werden anfangs übertragen und dann dynamisch in die Webseite nachgeladen. Bei Grafiken wird z.B. mit Sprites anstelle von Einzelgrafiken gearbeitet. So kann eine App schnell auf Nutzer und deren Interaktionen reagieren, es sollte aber trotzdem besonderer Wert auf eine geringe Gesamtgröße gelegt werden, damit potentielle Nutzer beim ersten Übertragen nicht frustriert wegen zu langer Ladezeiten abbrechen sollen.

Grundgerüst[Bearbeiten]

Die App besteht im Prinzip aus einer normalen Webseite, in der ein Browserspiel zu den Grundrechenarten angeboten wird.

Spielidee[Bearbeiten]

  1. Zwei zufällig ausgewählte Zahlen sollen miteinander berechnet werden.
  2. Der Operator wird über ein Auswahlmenü ausgewählt.
  3. Es soll eine Auswertung von Erfolg und Misserfolg geben

Das Spiel wird einzelne Funktionen aufgeteilt:

  1. eine Funktion createGame(), die das Spiel initialisiert und die gespeicherten Daten mit getSettings() aufruft
  2. eine Funktion task(), die
    1. zwei Zufallszahlen erzeugt und mit dem Operator ausgibt
    2. die Eingabe mit dem richtigen Ergebnis vergleicht
    3. die Ergebnistabelle aktualisiert
    4. wieder task() aufruft
  3. eine Funktion storeSettings(), die beim Verlassen des Spiels die Ergebnistabelle speichert
  4. eine Funktion getSettings(), die beim Start des Spiels die Ergebnistabelle lädt
  5. bei einer Änderungs des Operators über das Auswahlmenü soll die Funktion task() gestartet werden.

HTML[Bearbeiten]

Für das HTML-Markup sollte so weit wie möglich das Standardverhalten der Elemente genutzt werden. So wird das Auswahlmenü mit Radio-buttons realisiert:

Beispiel ansehen …
<form class="toggle-buttons" id="rechenarten"> 
   <input type="radio" name="op" id="add" checked><label for="add">+</label>
   <input type="radio" name="op" id="substract"> <label for="substract">-</label>
   <input type="radio" name="op" id="divide"> <label for="divide">÷</label>
   <input type="radio" name="op" id="multiply"> <label for="multiply">x</label>
   <input type="radio" name="op" id="any"> <label for="any" title="Zufallsauswahl">+ &nbsp; -<br>÷ &nbsp; x </label>   
</form>
Radio-Buttons, die über das gleiche name-Attribut verbunden sind, haben die nützliche Eigenschaft, dass jeweils nur ein Button ausgewählt werden kann. So muss nur noch mit JavaScript ausgelesen werden, welcher Button angeklickt wurde.


Die Rechenaufgabe besteht ebenfalls aus einem Formular:

Beispiel ansehen …
  <form id="task">
  <span id="var1">a</span>
  <span id="operator">+</span>
  <span id="var2">b</span> 
  =

    <input id="input" size="3">
    <button type="submit"></button>
  </form>  

<output>Ergebnisausgabe</output>
</p>
Für die beiden Zahlen und den Operator werden span-Elemente mit einer eindeutigen id verwendet. Das Ergebnisfeld besteht aus einem input-Element. Aus Gründen der Zugänglichkeit erhält es wie auch die Radio-Buttons oben ein label-Element mit einer Erklärung.

JavaScript[Bearbeiten]

createGame()[Bearbeiten]

Diese Funktion initialisiert das Spiel und ruft die gespeicherten Daten mit getSettings() auf. Danach wird die erste Aufgabe gestellt.

Beispiel ansehen …
  function createGame() {

  document.querySelector('#rechenarten').addEventListener('change', task);
  
  // gespeicherte Statistik laden. Wenn keine vorhanden, Info-Template laden
  // getSettings();

  task();
  }
Bei einer Änderungs des Operators über das Auswahlmenü soll die Funktion task() gestartet werden.


task()[Bearbeiten]

In der Funktion task() wird die eigentliche Rechenaufgabe gestellt. Zuerst wird der gewählte Operator ermittelt. Anschließend werden zwei Zufallszahlen erzeugt und mit dem Operator ausgegeben.

Um das Ergebnis zu ermitteln, sind verschiedene Wege möglich:

  • Zufallszahlen und Operator könnten zu einer Zeichenkette verknüpft und dann mit der globalen Funktion eval arithmetisch berechnet werden. Die Verwendung von eval ist jedoch mittlerweile verpönt und im strict mode verboten.
  • Eine sichere Alternative wäre ein eigener Parser wie der JavaScript Expression Evaluator
  • Im folgenden wird ein Objekt erzeugt, in dem für jeden Operator sowohl die Symbole als auch die Rechenoperation gespeichert werden. Für den Zufallsoperator werden die Operatoren dann mit der Zufallsfunktion ausgesucht.
Beispiel ansehen …
    var operator = document.querySelector('input[name="op"]:checked').id;
    var randomOps = [ 'add', 'substract', 'multiply', 'divide' ];
    var opMap = {
        "add": function(a, b) {
            return { symbol: "+", result: a+b };
        },
        "substract": function(a, b) {
            return { symbol: "-", result: a-b };
        },
        "multiply": function(a, b) {
            return { symbol: "×", result: a*b };
        },
        "divide": function(a, b) {
            return { symbol: "÷", result: a/b };
        },
        "any": function(a,b) {
                var op = rand(0, randomOps.length);
                return opMap[randomOps[op]](a,b);
             }
    };
Bei einer Änderungs des Operators über das Auswahlmenü soll die Funktion task() gestartet werden.
Beispiel ansehen …
  function task() {
    // vorherige Eingaben werden entfernt  
    output.textContent = 'Bitte gib das Ergebnis ein!';
    output.className = ''; 	
    document.getElementById('input').value = '';
	
    // gewählten Operator ermitteln; in einem Objekt sind für jeden Operator sowohl die Symbole als auch die Rechenoperation gespeichert. Für den Zufallsoperator werden die Operatoren dann mit der Zufallsfunktion ausgesucht.	
    var operator = document.querySelector('input[name="op"]:checked').id;
    var randomOps = [ 'add', 'substract', 'multiply', 'divide' ];
    var opMap = {
        "add": function(a, b) {
            return { symbol: "+", result: a+b };
        },
        "substract": function(a, b) {
            return { symbol: "-", result: a-b };
        },
        "multiply": function(a, b) {
            return { symbol: "×", result: a*b };
        },
        "divide": function(a, b) {
            return { symbol: "÷", result: a/b };
        },
        "any": function(a,b) {
                var op = rand(0, randomOps.length);
                return opMap[randomOps[op]](a,b);
             }
    };

    // Zufallszahlen ermitteln und mit Operator in task ausgeben
    var a = rand(5,12), 
        b = rand(1,9),
        operator = document.querySelector('input[name="op"]:checked').id,
        handler = opMap[operator];

    if (!handler) { /* Error */ }

	document.querySelector('#var1').textContent = a;
	document.querySelector('#var2').textContent = b;   
    var opInfo = handler(a,b);
    document.querySelector('#operator').textContent = opInfo.symbol;
    result = opInfo.result;
	
	// Ergebnis mit Eingabe vergleichen
    document.querySelector('#task').addEventListener('submit', function (evt) {
      evt.preventDefault();		
	  input = document.getElementById('input').value;

	  if (result == input){
        output.textContent = 'Super!';
		output.className = 'exact'; 
      } else {
        document.querySelector('output').textContent = 'Leider falsch!';
		output.className = 'inexact'; 		
      }	
	setTimeout(task, 1000);
	});
Nachdem Ausgabe und Eingabe wieder zurückgesetzt wurden, wird mit .


  1. die Eingabe mit dem richtigen Ergebnis vergleicht
  2. die Ergebnistabelle aktualisiert
  3. wieder task() aufruft

Speichern und Auslesen der Statistik[Bearbeiten]

eine Funktion storeSettings(), die beim Verlassen des Spiels die Ergebnistabelle speichert

  1. eine Funktion getSettings(), die beim Start des Spiels die Ergebnistabelle lädt

Offline-Verfügbarkeit[Bearbeiten]

Offline-Browsing mit dem manifest-Attribut


Wie bei fast jedem neuen Feature steht auch hier schon wieder ein Nachfolger vor der Tür. Mit der WebSocket API können Sie ohne HTTP-Requests zwischen Server und Endgeräte kommunizieren.

Icon für das Startmenü[Bearbeiten]

  • Icon auf Startbildschirm

Quellen[Bearbeiten]

  1. smashingmagazone: The Building Blocks Of Progressive Web Apps “But It’s Not In An App Store” (05.09.2016)
  2. elektronik-kompendium: Latenzzeit, die Spaßbremse im Mobilfunknetz


Weblinks[Bearbeiten]

Einführungen

Tutorials

Self-Forum