Aufbau für moderne Browser und schrittweise Verbesserung wie im Jahr 2003
Aktualisiert
Progressive Web Apps
Bereits im März 2003 Nick Finck und
Steve Champeon betäubte die Webdesign-Welt
mit dem Konzept von
Progressive Enhancement,
eine Strategie für das Webdesign, bei der das Laden des Kerninhalts der Webseite an erster Stelle steht:
und das fügt dann nach und nach nuancierter hinzu
und technisch strenge Ebenen der Präsentation und Funktionen über dem Inhalt.
Während im Jahr 2003 bei der progressiven Verbesserung die Verwendung von Modern zu dieser Zeit im Vordergrund stand
CSS-Funktionen, unauffälliges JavaScript und sogar nur skalierbare Vektorgrafiken.
Bei der schrittweisen Verbesserung im Jahr 2020 und darüber hinaus geht es um die Verwendung
moderne Browserfunktionen.
Modernes JavaScript
Apropos JavaScript, die Browser-Unterstützungssituation für das neueste Kern-ES 2015-JavaScript
Funktionen ist großartig.
Der neue Standard enthält Versprechen, Module, Klassen, Vorlagenliterale, Pfeilfunktionen, Lassen
und const
,
Standardparameter, Generatoren, die Destrukturierungszuweisung, Ruhe und Ausbreitung, Karte
/einstellen
,
Schwache Karte
/WeakSet
, und viele mehr.
Alle werden unterstützt.
Async-Funktionen, eine ES 2017-Funktion und einer meiner persönlichen Favoriten,
kann verwendet werden
in allen gängigen Browsern.
Das asynchron
und erwarten
Schlüsselwörter ermöglichen asynchrones, auf Versprechen basierendes Verhalten
in einem saubereren Stil geschrieben werden, ohne dass Versprechensketten explizit konfiguriert werden müssen.
Und selbst super aktuelle ES 2020 Sprachzusätze wie
optionale Verkettung und
nullish verschmelzen
haben sehr schnell Unterstützung erreicht. Unten sehen Sie ein Codebeispiel.
Wenn es um JavaScript-Kernfunktionen geht, könnte das Gras nicht viel grüner sein als es
ist heute.
const adventurer = {
Süßkartoffel: 'Alice',
cat: {
Süßkartoffel: 'Dinah',
},
};
console.Log(adventurer.dog?.Süßkartoffel);
console.Log(0 ?? 42);
Die Beispiel-App: Fugu Greetings
Für diesen Artikel arbeite ich mit einer einfachen PWA namens
Fugu Grüße
(GitHub).
Der Name dieser App ist ein Tipp für Project Fugu®, ein Versuch, dem Web alles zu geben
die Möglichkeiten nativer Anwendungen.
Sie können mehr über das Projekt auf seiner lesen
Zielseite.
Fugu Greetings ist eine Zeichen-App, mit der Sie virtuelle Grußkarten erstellen und senden können
sie zu Ihren Lieben. Es veranschaulicht
Kernkonzepte von PWA. Es ist
zuverlässig und vollständig offline aktiviert, auch wenn Sie dies nicht tun
Haben Sie ein Netzwerk, können Sie es weiterhin verwenden. Es ist auch installierbar
auf den Startbildschirm eines Geräts und lässt sich nahtlos in das Betriebssystem integrieren
als eigenständige Anwendung.
Progressive Enhancement
Wenn dies aus dem Weg ist, ist es Zeit, darüber zu sprechen Progressive Enhancement.
Das MDN Web Docs Glossar Sie definieren
das Konzept wie folgt:
Progressive Enhancement ist eine Designphilosophie, die eine Grundlinie von bietet
wesentliche Inhalte und Funktionen für möglichst viele Benutzer
Bereitstellung der bestmöglichen Erfahrung nur für Benutzer der modernsten
Browser, die den gesamten erforderlichen Code ausführen können.Funktionserkennung
wird im Allgemeinen verwendet, um festzustellen, ob Browser mit moderneren Funktionen umgehen können.
während Polyfüllungen
werden häufig verwendet, um fehlende Funktionen mit JavaScript hinzuzufügen.[…]
Die progressive Verbesserung ist eine nützliche Technik, mit der sich Webentwickler konzentrieren können
über die Entwicklung der bestmöglichen Websites, während diese Websites funktionieren
auf mehreren unbekannten Benutzeragenten.
Anmutige Erniedrigung
ist verwandt, aber nicht dasselbe und wird oft als in die entgegengesetzte Richtung gehend angesehen
zur fortschreitenden Verbesserung.
In der Realität sind beide Ansätze gültig und können sich häufig ergänzen.
MDN-Mitwirkende
Das Starten jeder Grußkarte von Grund auf kann sehr umständlich sein.
Warum also nicht eine Funktion haben, mit der Benutzer ein Bild importieren und von dort aus starten können?
Mit einem traditionellen Ansatz hätten Sie einen verwendet
Element, um dies zu ermöglichen.
Zuerst würden Sie das Element erstellen und es festlegen Art
zu 'Datei'
und fügen Sie dem MIME-Typen hinzu akzeptieren
Eigentum,
und dann programmgesteuert darauf "klicken" und auf Änderungen warten.
Wenn Sie ein Bild auswählen, wird es direkt auf die Leinwand importiert.
const importImage = asynchron () => {
Rückkehr new Promise((resolve) => {
const Eingang = Dokument.createElement('input');
Eingang.Art = 'Datei';
Eingang.akzeptieren = 'image/*';
Eingang.addEventListener('change', () => {
resolve(Eingang.Dateien[0]);
});
Eingang.klicken();
});
};
Wenn es eine gibt importieren Feature sollte es wohl eine geben Export Feature
So können Benutzer ihre Grußkarten lokal speichern.
Die herkömmliche Methode zum Speichern von Dateien besteht darin, einen Ankerlink zu erstellen
mit einer herunterladen
Attribut und mit einer Blob-URL als seine href
.
Sie würden auch programmgesteuert darauf "klicken", um den Download auszulösen.
Um Speicherlecks zu vermeiden, vergessen Sie hoffentlich nicht, die URL des Blob-Objekts zu widerrufen.
const exportImage = asynchron (Klecks) => {
const zu = Dokument.createElement('a');
zu.herunterladen = 'fugu-greeting.png';
zu.href = Url.createObjectURL(Klecks);
zu.addEventListener('click', (und) => {
setTimeout(() => Url.revokeObjectURL(zu.href), 30 * 1000);
});
zu.klicken();
};
Aber warte eine Minute. Geistig haben Sie noch keine Grußkarte «heruntergeladen»
«Gespeichert».
Anstatt Ihnen ein Dialogfeld zum Speichern anzuzeigen, in dem Sie auswählen können, wo die Datei abgelegt werden soll,
Der Browser hat die Grußkarte ohne Benutzerinteraktion direkt heruntergeladen
und hat es direkt in Ihren Downloads-Ordner gelegt. Das ist nicht so toll.
Was wäre, wenn es einen besseren Weg gäbe?
Was wäre, wenn Sie einfach eine lokale Datei öffnen, bearbeiten und dann die Änderungen speichern könnten?
entweder in eine neue Datei oder zurück in die ursprüngliche Datei, die Sie ursprünglich geöffnet hatten?
Es stellt sich heraus, dass es gibt. Die native Dateisystem-API
ermöglicht es Ihnen, Dateien zu öffnen und zu erstellen und
Verzeichnisse sowie ändern und speichern.
Wie erkenne ich eine API?
Die native Dateisystem-API stellt eine neue Methode zur Verfügung window.chooseFileSystemEntries ()
.
Folglich muss ich verschiedene Import- und Exportmodule bedingt laden, je nachdem, ob diese Methode verfügbar ist. Ich habe unten gezeigt, wie das geht.
const loadImportAndExport = () => {
wenn ('chooseFileSystemEntries' im Fenster) {
Promise.Dort([
importieren('./import_image.mjs'),
importieren('./export_image.mjs'),
]);
} else {
Promise.Dort([
importieren('./import_image_legacy.mjs'),
importieren('./export_image_legacy.mjs'),
]);
}
};
Bevor ich mich jedoch mit den Details der Native File System-API befasse,
Lassen Sie mich hier nur kurz das progressive Verbesserungsmuster hervorheben.
In Browsern, die derzeit die native Dateisystem-API nicht unterstützen, lade ich die Legacy-Skripte.
Unten sehen Sie die Netzwerkregisterkarten von Firefox und Safari.
In Chrome, einem Browser, der die API unterstützt, werden jedoch nur die neuen Skripts geladen.
Dies wird dank elegant ermöglicht
dynamisch importieren ()
, die alle modernen Browser
Unterstützung.
Wie ich bereits sagte, ist das Gras heutzutage ziemlich grün.
Die native Dateisystem-API
Nachdem ich dies angesprochen habe, ist es an der Zeit, die tatsächliche Implementierung basierend auf der Native File System-API zu betrachten.
Zum Importieren eines Bildes rufe ich an window.chooseFileSystemEntries ()
und gib es weiter akzeptiert
Eigenschaft, wo ich sage, ich möchte Bilddateien.
Es werden sowohl Dateierweiterungen als auch MIME-Typen unterstützt.
Dies führt zu einem Dateihandle, von dem ich die eigentliche Datei durch Aufrufen abrufen kann eine Datei bekommen ()
.
const importImage = asynchron () => {
try {
const handle = erwarten Fenster.chooseFileSystemEntries({
akzeptiert: [
{
Beschreibung: 'Image files',
mimeTypes: ['image/*'],
Erweiterungen: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
Rückkehr handle.getFile();
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Das Exportieren eines Bildes ist fast dasselbe, diesmal jedoch
Ich muss einen Typparameter von übergeben 'Datei speichern'
zum selectFileSystemEntries ()
Methode.
Daraus erhalte ich einen Dialog zum Speichern von Dateien.
Bei geöffneter Datei war dies seitdem nicht mehr erforderlich 'Datei öffnen'
ist die Standardeinstellung.
Ich stelle das ein akzeptiert
Parameter ähnlich wie zuvor, diesmal jedoch nur auf PNG-Bilder beschränkt.
Wieder bekomme ich ein Dateihandle zurück, aber anstatt die Datei zu bekommen,
Dieses Mal erstelle ich einen beschreibbaren Stream, indem ich aufrufe createWritable ()
.
Als nächstes schreibe ich den Blob, der mein Grußkartenbild ist, in die Datei.
Schließlich schließe ich den beschreibbaren Stream.
Alles kann immer fehlschlagen: Auf der Festplatte ist möglicherweise nicht genügend Speicherplatz vorhanden.
Möglicherweise liegt ein Schreib- oder Lesefehler vor, oder der Benutzer bricht den Dateidialog einfach ab.
Deshalb verpacke ich die Anrufe immer in a versuche ... zu fangen
Aussage.
const exportImage = asynchron (Klecks) => {
try {
const handle = erwarten Fenster.chooseFileSystemEntries({
Art: 'Datei speichern',
akzeptiert: [
{
Beschreibung: 'Image file',
Erweiterungen: ['png'],
mimeTypes: ['image/png'],
},
],
});
const schreibbar = erwarten handle.createWritable();
erwarten schreibbar.write(Klecks);
erwarten schreibbar.close();
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Verwenden der progressiven Erweiterung mit der Native File System API,
Ich kann eine Datei wie zuvor öffnen.
Die importierte Datei wird direkt auf die Leinwand gezeichnet.
Ich kann meine Änderungen vornehmen und sie schließlich in einem echten Dialogfeld zum Speichern speichern
Hier kann ich den Namen und den Speicherort der Datei auswählen.
Jetzt kann die Datei für die Ewigkeit aufbewahrt werden.
Die Web Share- und Web Share-Ziel-APIs
Abgesehen von der Aufbewahrung für die Ewigkeit möchte ich vielleicht tatsächlich meine Grußkarte teilen.
Dies ist etwas, das die Web Share API und
Mit der Web Share Target-API kann ich dies tun.
Mobile und in jüngerer Zeit Desktop-Betriebssysteme haben native Freigabe erhalten
Mechanismen.
Im Folgenden finden Sie beispielsweise das Freigabeblatt von Desktop Safari unter macOS, das aus einem Artikel über ausgelöst wurde
meine Blog.
Wenn Sie auf die klicken Artikel teilen Schaltfläche können Sie einen Link zum Artikel mit einem Freund teilen, z
Beispiel über die native macOS Messages App.
Der Code, um dies zu erreichen, ist ziemlich einfach. Ich rufe navigator.share ()
und
Übergeben Sie es optional Titel
, Text
, und URL
in einem Objekt.
Aber was ist, wenn ich ein Bild anhängen möchte? Level 1 der Web Share API unterstützt dies noch nicht.
Die gute Nachricht ist, dass Web Share Level 2 Dateifreigabefunktionen hinzugefügt hat.
try {
erwarten Navigator.Compartir({
Titel: 'Check out this article:',
Text: `"${Dokument.Titel}" by @tomayac:`,
URL: Dokument.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warnen(err.Süßkartoffel, err.Botschaft);
}
Lassen Sie mich Ihnen zeigen, wie dies mit der Fugu-Grußkartenanwendung funktioniert.
Zuerst muss ich eine vorbereiten Daten
Objekt mit a Dateien
Array bestehend aus einem Blob und dann
zu Titel
und ein Text
. Als nächstes verwende ich als Best Practice das Neue navigator.canShare ()
Methode, die tut
was sein Name andeutet:
Es sagt mir, ob die Daten
Das Objekt, das ich freigeben möchte, kann vom Browser technisch freigegeben werden.
Wenn navigator.canShare ()
sagt mir, dass die Daten geteilt werden können, ich bin bereit dazu
Anruf navigator.share ()
wie vorher.
Weil alles scheitern kann, benutze ich wieder a versuche ... zu fangen
Block.
const Compartir = asynchron (Titel, Text, Klecks) => {
const Daten = {
Dateien: [
new Datei([Klecks], 'fugu-greeting.png', {
Art: Klecks.Art,
}),
],
Titel: Titel,
Text: Text,
};
try {
wenn (!(Navigator.canShare(Daten))) {
throw new Error("Can't share data.", Daten);
}
erwarten Navigator.Compartir(Daten);
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Nach wie vor verwende ich die progressive Verbesserung.
Wenn beides "Compartir"
und 'kann Teilen'
existieren auf der Navigator
Objekt, erst dann gehe ich vorwärts und
Belastung share.mjs
über dynamisch importieren ()
.
In Browsern wie Mobile Safari, die nur eine der beiden Bedingungen erfüllen, lade ich nicht
die Funktionalität.
const loadShare = () => {
wenn ("Compartir" im Navigator && 'kann Teilen' im Navigator) {
importieren('./share.mjs');
}
};
In Fugu-Grüßen, wenn ich auf tippe Compartir Schaltfläche in einem unterstützenden Browser wie Chrome auf Android,
Das native Freigabeblatt wird geöffnet.
Ich kann zum Beispiel Google Mail auswählen, und das E-Mail-Composer-Widget wird mit dem angezeigt
Bild angehängt.
Als nächstes möchte ich über Kontakte sprechen, dh das Adressbuch eines Geräts
oder Kontakte Manager App.
Wenn Sie eine Grußkarte schreiben, ist es möglicherweise nicht immer einfach, richtig zu schreiben
jemandes Name.
Zum Beispiel habe ich einen Freund Sergey, der es vorzieht, seinen Namen in kyrillischen Buchstaben zu schreiben. Ich bin
mit einer deutschen QWERTZ-Tastatur und haben keine Ahnung, wie sie ihren Namen eingeben sollen.
Dies ist ein Problem, das die Contact Picker-API lösen kann.
Da ich meinen Freund in der Kontakt-App meines Telefons gespeichert habe,
Über die Contacts Picker-API kann ich meine Kontakte über das Web abrufen.
Zuerst muss ich die Liste der Eigenschaften angeben, auf die ich zugreifen möchte.
In diesem Fall möchte ich nur die Namen,
Für andere Anwendungsfälle interessieren mich möglicherweise Telefonnummern, E-Mails und Avatare
Symbole oder physische Adressen.
Als nächstes konfiguriere ich eine Optionen
Objekt und setzen mehrere
zu wahr
, damit ich mehr auswählen kann
als ein Eintrag.
Endlich kann ich anrufen navigator.contacts.select ()
, die die gewünschten Eigenschaften zurückgibt
für die vom Benutzer ausgewählten Kontakte.
const getContacts = asynchron () => {
const properties = ['name'];
const Optionen = { mehrere: wahr };
try {
Rückkehr erwarten Navigator.contacts.select(properties, Optionen);
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Und jetzt haben Sie wahrscheinlich das Muster gelernt:
Ich lade die Datei nur, wenn die API tatsächlich unterstützt wird.
wenn ('contacts' im Navigator) {
importieren('./contacts.mjs');
}
In Fugu Greeting, wenn ich auf tippe Kontakte Knopf und wählen Sie meine zwei besten Freunde,
Сергей Михайлович Брин und 劳伦斯 · 爱德华 · »拉里» · 佩奇,
Sie können sehen, wie die
Die Kontaktauswahl ist darauf beschränkt, nur ihre Namen anzuzeigen.
aber nicht ihre E-Mail-Adressen oder andere Informationen wie ihre Telefonnummern.
Ihre Namen werden dann auf meine Grußkarte gezeichnet.
Die API für die asynchrone Zwischenablage
Als nächstes wird kopiert und eingefügt.
Eine unserer Lieblingsoperationen als Softwareentwickler ist das Kopieren und Einfügen.
Als Grußkartenautor möchte ich manchmal das Gleiche tun.
Ich möchte vielleicht entweder ein Bild in eine Grußkarte einfügen, an der ich arbeite.
oder kopieren Sie meine Grußkarte, damit ich sie weiter bearbeiten kann
irgendwo anders.
Die Async-Zwischenablage-API,
unterstützt sowohl Text als auch Bilder.
Lassen Sie mich Ihnen zeigen, wie ich dem Fugu Unterstützung beim Kopieren und Einfügen hinzugefügt habe
Grüße App.
Um etwas in die Zwischenablage des Systems zu kopieren, muss ich darauf schreiben.
Das navigator.clipboard.write ()
Methode nimmt ein Array von Zwischenablage-Elementen als
Parameter.
Jedes Element in der Zwischenablage ist im Wesentlichen ein Objekt mit einem Blob als Wert und dem Typ des Blobs
als Schlüssel.
const Kopieren = asynchron (Klecks) => {
try {
erwarten Navigator.Zwischenablage.write([
new ClipboardItem({
[Klecks.Art]: Klecks,
}),
]);
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Zum Einfügen muss ich die Elemente der Zwischenablage durchlaufen, die ich durch Aufrufen erhalte
navigator.clipboard.read ()
.
Der Grund dafür ist, dass sich möglicherweise mehrere Elemente der Zwischenablage in der Zwischenablage befinden
verschiedene Darstellungen.
Jedes Zwischenablageelement hat eine Typen
Feld, das mir die MIME-Typen der verfügbaren angibt
Ressourcen.
Ich rufe die Zwischenablage an getType ()
Methode, die übergeben
MIME-Typ, den ich zuvor erhalten habe.
const Einfügen = asynchron () => {
try {
const clipboardItems = erwarten Navigator.Zwischenablage.read();
zum (const clipboardItem of clipboardItems) {
try {
zum (const Art of clipboardItem.Typen) {
const Klecks = erwarten clipboardItem.getType(Art);
Rückkehr Klecks;
}
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
}
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Und es ist mittlerweile fast unnötig zu sagen. Ich mache das nur bei der Unterstützung von Browsern.
wenn ('clipboard' im Navigator && 'write' im Navigator.Zwischenablage) {
importieren('./clipboard.mjs');
}
Wie funktioniert das in der Praxis? Ich habe ein Bild in der macOS Preview App geöffnet und
Kopieren Sie es in die Zwischenablage.
Wenn ich klicke Einfügenfragt mich dann die Fugu Greetings App
ob ich der App erlauben möchte, Text und Bilder in der Zwischenablage anzuzeigen.
Nachdem Sie die Berechtigung akzeptiert haben, wird das Bild in die Anwendung eingefügt.
Umgekehrt funktioniert es auch.
Lassen Sie mich eine Grußkarte in die Zwischenablage kopieren.
Wenn ich dann Vorschau öffne und klicke Datei und dann Neu aus der Zwischenablage,
Die Grußkarte wird in ein neues Bild ohne Titel eingefügt.
Die Badging-API
Eine weitere nützliche API ist die Badging-API.
Als installierbare PWA hat Fugu Greetings natürlich ein App-Symbol
die Benutzer auf dem App-Dock oder dem Startbildschirm platzieren können.
Eine unterhaltsame und einfache Möglichkeit, die API zu demonstrieren, besteht darin, sie in Fugu-Grüßen (ab) zu verwenden
als Stift streichelt Zähler.
Ich habe einen Ereignis-Listener hinzugefügt, der den Zähler für Stiftstriche erhöht, wenn der Zeiger nach unten
Ereignis tritt ein
und setzt dann das aktualisierte Symbolabzeichen.
Immer wenn die Leinwand gelöscht wird, wird der Zähler zurückgesetzt und das Abzeichen entfernt.
Lassen strokes = 0;canvas.addEventListener('pointerdown', () => {
Navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
Navigator.setAppBadge(strokes);
});
Diese Funktion ist eine progressive Verbesserung, daher ist die Ladelogik wie gewohnt.
wenn ('setAppBadge' im Navigator) {
importieren('./badge.mjs');
}
In diesem Beispiel habe ich die Zahlen mit einem Stiftstrich von eins bis sieben gezeichnet
pro Nummer.
Der Ausweiszähler auf dem Symbol ist jetzt um sieben.
Die periodische Hintergrundsynchronisierungs-API
Möchten Sie jeden Tag neu mit etwas Neuem beginnen?
Eine nette Funktion der Fugu Greetings App ist, dass sie Sie jeden Morgen inspirieren kann
mit einem neuen Hintergrundbild, um Ihre Grußkarte zu starten.
Die App verwendet die Periodic Background Sync API
um das zu erreichen.
Der erste Schritt ist zu registrieren Ein periodisches Synchronisierungsereignis in der Servicemitarbeiterregistrierung.
Es wartet auf ein Sync-Tag namens "Bild des Tages"
und hat ein Mindestintervall von einem Tag,
So kann der Benutzer alle 24 Stunden ein neues Hintergrundbild erhalten.
const registerPeriodicBackgroundSync = asynchron () => {
const Anmeldung = erwarten Navigator.serviceWorker.bereit;
try {
Anmeldung.periodicSync.registrieren('image-of-the-day-sync', {
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.Error(err.Süßkartoffel, err.Botschaft);
}
};
Der zweite Schritt ist zu Hör mal zu für die periodicsync
Ereignis im Servicemitarbeiter.
Wenn das Ereignistag ist "Bild des Tages"
das heißt, derjenige, der zuvor registriert wurde,
Das Bild des Tages wird über das abgerufen getImageOfTheDay ()
Funktion,
und das Ergebnis wird an alle Clients weitergegeben, damit diese ihre Leinwände und aktualisieren können
Caches.
selbst.addEventListener('periodicsync', (syncEvent) => {
wenn (syncEvent.Etikett === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(asynchron () => {
const Klecks = erwarten getImageOfTheDay();
const clients = erwarten selbst.clients.matchAll();
clients.forEach((client) => {
client.POST-Meldung({
Bild: Klecks,
});
});
})()
);
}
});
Auch dies ist wirklich eine progressive Verbesserung, so dass der Code nur geladen wird, wenn die
Die API wird vom Browser unterstützt.
Dies gilt sowohl für den Client-Code als auch für den Service-Worker-Code.
In nicht unterstützten Browsern wird keiner von ihnen geladen.
Beachten Sie, wie im Service Worker anstelle einer Dynamik importieren ()
(Dies wird in einem Service Worker-Kontext nicht unterstützt
noch),
Ich benutze den Klassiker
importScripts ()
.
const Anmeldung = erwarten Navigator.serviceWorker.bereit;
wenn (Anmeldung && 'periodicSync' im Anmeldung) {
importieren('./periodic_background_sync.mjs');
}
wenn ('periodicSync' im selbst.Anmeldung) {
importScripts('./image_of_the_day.mjs');
}
Drücken Sie in Fugu Greetings die Taste Hintergrund Schaltfläche zeigt das Grußkartenbild des Tages
Dies wird jeden Tag über die Periodic Background Sync API aktualisiert.
Benachrichtigung löst API aus
Manchmal braucht man sogar mit viel Inspiration einen Schubs, um eine begonnene Begrüßung zu beenden
Karte.
Dies ist eine Funktion, die von der Notification Triggers API aktiviert wird.
Als Benutzer kann ich eine Zeit eingeben, zu der ich angestupst werden möchte, um meine Grußkarte fertigzustellen.
Wenn diese Zeit gekommen ist, erhalte ich eine Benachrichtigung, dass meine Grußkarte wartet.
Nach Aufforderung zur Eingabe der Zielzeit,
Die Anwendung plant die Benachrichtigung mit a showTrigger
.
Dies kann ein sein TimestampTrigger
mit dem zuvor ausgewählten Zieldatum.
Die Erinnerungsbenachrichtigung wird lokal ausgelöst, es wird keine Netzwerk- oder Serverseite benötigt.
const targetDate = promptTargetDate();
wenn (targetDate) {
const Anmeldung = erwarten Navigator.serviceWorker.bereit;
Anmeldung.showNotification('Reminder', {
Etikett: 'reminder',
Körper: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
Wie bei allem anderen, was ich bisher gezeigt habe, ist dies eine progressive Verbesserung.
Der Code wird also nur bedingt geladen.
wenn ('Notification' im Fenster && 'showTrigger' im Notification.prototype) {
importieren('./notification_triggers.mjs');
}
Wenn ich das überprüfe Erinnerung Kontrollkästchen in Fugu Greetings, fragt eine Eingabeaufforderung
mich, wenn ich daran erinnert werden möchte, meine Grußkarte fertig zu stellen.
Wenn eine geplante Benachrichtigung in Fugu Greetings ausgelöst wird,
es wird wie jede andere Benachrichtigung angezeigt, aber wie ich zuvor geschrieben habe,
Es war keine Netzwerkverbindung erforderlich.
Die Wake Lock API
Ich möchte auch die Wake Lock API einbinden.
Manchmal muss man nur lange genug am Bildschirm stehen, bis man sich inspirieren lässt
küsst dich
Das Schlimmste, was dann passieren kann, ist, dass sich der Bildschirm ausschaltet.
Die Wake Lock-API kann dies verhindern.
Der erste Schritt besteht darin, eine Wake-Sperre mit dem zu erhalten navigator.wakelock.request method ()
.
Ich gebe ihm die Schnur 'Bildschirm'
um eine Bildschirm-Wake-Sperre zu erhalten.
Ich füge dann einen Ereignis-Listener hinzu, der informiert wird, wenn die Wecksperre aufgehoben wird.
Dies kann beispielsweise passieren, wenn sich die Sichtbarkeit der Registerkarte ändert.
In diesem Fall kann ich die Wecksperre wiederherstellen, wenn die Registerkarte wieder sichtbar wird.
Lassen wakeLock = Null;
const requestWakeLock = asynchron () => {
wakeLock = erwarten Navigator.wakeLock.request('Bildschirm');
wakeLock.addEventListener('release', () => {
console.Log('Wake Lock was released');
});
console.Log('Wake Lock is active');
};const handleVisibilityChange = () => {
wenn (wakeLock !== Null && Dokument.visibilityState === 'visible') {
requestWakeLock();
}
};
Dokument.addEventListener('visibilitychange', handleVisibilityChange);
Dokument.addEventListener('fullscreenchange', handleVisibilityChange);
Ja, dies ist eine progressive Verbesserung, daher muss ich sie nur laden, wenn der Browser
unterstützt die API.
wenn ('wakeLock' im Navigator && 'request' im Navigator.wakeLock) {
importieren('./wake_lock.mjs');
}
In Fugu Greetings gibt es eine Schlaflosigkeit Kontrollkästchen, das, wenn aktiviert, die
Bildschirm wach.
Die Leerlauferkennungs-API
Manchmal, selbst wenn Sie stundenlang auf den Bildschirm starren,
Es ist einfach nutzlos und Sie können sich nicht die geringste Idee einfallen lassen, was Sie mit Ihrer Grußkarte tun sollen.
Mit der Leerlauferkennungs-API kann die App die Leerlaufzeit des Benutzers erkennen.
Wenn der Benutzer zu lange inaktiv ist, wird die App auf den Ausgangszustand zurückgesetzt
und löscht die Leinwand.
Diese API befindet sich derzeit hinter dem
Benachrichtigungserlaubnis,
Da viele Anwendungsfälle der Leerlauferkennung in der Produktion mit Benachrichtigungen zusammenhängen,
Um beispielsweise nur eine Benachrichtigung an ein Gerät zu senden, das der Benutzer derzeit aktiv verwendet.
Nachdem ich sichergestellt habe, dass die Benachrichtigungsberechtigung erteilt wurde, instanziiere ich die
Leerlaufdetektor.
Ich registriere einen Ereignis-Listener, der auf Änderungen im Leerlauf wartet, einschließlich des Benutzers und
den Bildschirmstatus.
Der Benutzer kann aktiv oder inaktiv sein.
und der Bildschirm kann entsperrt oder gesperrt werden.
Wenn der Benutzer inaktiv ist, wird die Zeichenfläche gelöscht.
Ich gebe dem Leerlaufdetektor eine Schwelle von 60 Sekunden.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.Log(`Idle change: ${userState}, ${screenState}.`);
wenn (userState === 'idle') {
clearCanvas();
}
});erwarten idleDetector.Start({
Schwelle: 60000,
Signal,
});
Und wie immer lade ich diesen Code nur, wenn der Browser ihn unterstützt.
wenn ('IdleDetector' im Fenster) {
importieren('./idle_detection.mjs');
}
In der Fugu Greetings-App wird die Leinwand gelöscht, wenn die Flüchtig Kontrollkästchen ist
aktiviert und der Benutzer ist zu lange inaktiv.
Schließen
Puh, was für eine Fahrt. So viele APIs in nur einer Beispiel-App.
Und denken Sie daran, ich lasse den Benutzer niemals die Downloadkosten bezahlen
für eine Funktion, die ihr Browser nicht unterstützt.
Durch die Verwendung der progressiven Verbesserung stelle ich sicher, dass nur der relevante Code geladen wird.
Und da mit HTTP / 2 Anfragen billig sind, sollte dieses Muster für viele gut funktionieren
Anwendungen,
obwohl Sie vielleicht einen Bundler für wirklich große Apps in Betracht ziehen möchten.
Die App sieht in jedem Browser möglicherweise etwas anders aus, da nicht alle Plattformen alle Funktionen unterstützen.
Die Kernfunktionalität ist jedoch immer vorhanden - entsprechend den Funktionen des jeweiligen Browsers.
Beachten Sie, dass sich diese Funktionen auch in ein und demselben Browser ändern können.
Dies hängt davon ab, ob die App als installierte App oder in einer Browser-Registerkarte ausgeführt wird.
Wenn Sie an der interessiert sind Fugu Grüße App,
geh finden und Gabel es auf GitHub.
Das Chromium-Team arbeitet hart daran, das Gras grüner zu machen, wenn es um fortschrittliche Fugu-APIs geht.
Durch die schrittweise Verbesserung der Entwicklung meiner App
Ich stelle sicher, dass jeder eine gute, solide Grunderfahrung macht.
Menschen, die Browser verwenden, die mehr Webplattform-APIs unterstützen, erhalten jedoch eine noch bessere Erfahrung.
Ich freue mich darauf zu sehen, was Sie mit der progressiven Verbesserung Ihrer Apps tun.
Danksagung
Ich bin dankbar dafür Christlicher Liebel und
Hemanth HM die beide zu Fugu Greetings beigetragen haben.
Dieser Artikel wurde von überprüft Joe Medley und
Kayce Basques.
Jake Archibald hat mir geholfen, die Situation herauszufinden
mit dynamischer importieren ()
in einem Service-Worker-Kontext.