Zum Hauptinhalt springen

Aufbau für moderne Browser und schrittweise Verbesserung wie im Jahr 2003


Aktualisiert

Erscheint in:
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.

100002010000053c000003e8b978fe17e590bc9a-2242580
Folie: Inklusives Webdesign für die Zukunft mit progressiver Verbesserung.
(Quelle)

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.

igraal_de-de
10000000000009c40000039ef0a6fe5c50e42dea-1991285
Die Browser-Support-Tabelle für ECMAScript 2015 (ES6). ((Quelle)

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.

10000000000009c400000304a19ef0ff1d72987d-1299321
Die Browser-Supporttabelle für Async-Funktionen. ((Quelle)

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 = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
console.log(0 ?? 42);

1000020100000640000003e810e16d93c747b2d5-1385902
Das Gras ist grün, wenn es um die wichtigsten JavaScript-Funktionen geht.
(Microsoft-Produkt-Screenshot, verwendet mit
Genehmigung.)

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.

10000201000009c4000006a2f58b840608cea761-4971462
Das Fugu Grüße Beispiel App.

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 = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};

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 (blob) => {
const a = Dokument . createElement ( 'a' ) ;
a . download = 'fugu-greeting.png' ;
a . href = URL . createObjectURL ( Blob ) ;
a . addEventListener ( 'click' , ( e ) => {
setTimeout ( ( ) => URL . revokeObjectURL ( a . href ) , 30 * 1000 ) ;
} ) ;
a . click ( ) ;
} ;

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 = ( ) => {
if ( 'ChooseFileSystemEntries' im Fenster ) {
Versprich es mir . alle ( [
import ( './import_image.mjs' ) ,
import ( './export_image.mjs' ) ,
] ) ;
} else {
Versprich es mir . alle ( [
import ( './import_image_legacy.mjs' ) ,
import ( './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.

100002010000058c000000ca65613fec1d7fb3e2-1128402
Registerkarte "Netzwerk" von Safari Web Inspector.
10000201000005800000012430b7b8786bf315dd-5981940
Registerkarte "Netzwerk" der Firefox Developer Tools.

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.

10000201000006fc0000021ad16a28ba8f5cbf1a-3614115
Registerkarte "Chrome DevTools-Netzwerk".

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 = async ( ) => {
versuche {
const handle = Wartefenster . selectFileSystemEntries ( {
akzeptiert : [
{
Beschreibung : 'Bilddateien' ,
mimeTypes : [ 'image / *' ] ,
Erweiterungen : [ 'jpg' , 'jpeg' , 'png' , 'webp' , 'svg' ] ,
} ,
] ,
} ) ;
Rückgabegriff . getFile ( ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 (blob) => {
versuche {
const handle = Wartefenster . selectFileSystemEntries ( {
Typ : 'Datei speichern' ,
akzeptiert : [
{
Beschreibung : 'Bilddatei' ,
Erweiterungen : [ 'png' ] ,
mimeTypes : [ 'image / png' ] ,
} ,
] ,
} ) ;
const writable = warte auf handle . createWritable ( ) ;
warte beschreibbar . schreiben ( Blob ) ;
warte beschreibbar . close ( ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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.

10000201000009c4000005db39851711e3cb3bf0-1180658
Der Dialog zum Öffnen der Datei.
10000201000009c4000005db01941257d7be6a85-4907083
Das importierte Bild.
10000201000009c4000005dbcbe1b58ec828bb29-9444761
Speichern des geänderten Bildes in einer neuen Datei.

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.

1000020100000356000001c434f5dd5d64721768-4082576
Web Share API auf Desktop Safari unter MacOS.

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.

versuche {
warte auf navigator . teilen ( {
Titel : 'Schauen Sie sich diesen Artikel an:' ,
Text : ` " $ { document . title } "von @tomayac: ` ,
URL : Dokument . querySelector ( 'link [rel = canonical]' ) . href ,
} ) ;
} catch ( err ) {
Konsole . warn ( err . name , err . message ) ;
}}

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 share = async ( Titel , Text , Blob ) => {
const data = {
Dateien : [
neue Datei ( [ blob ] , 'fugu-greeting.png' , {
Typ : Blob . Typ ,
} ) ,
] ,
Titel : Titel ,
Text : Text ,
} ;
versuche {
if ( ! ( navigator . canShare ( data ) ) ) {
throw new Error ( "Daten können nicht teilen.", Daten);
}}
warte auf navigator . teilen ( Daten ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 = ( ) => {
if ( 'share' im Navigator && 'canShare' im Navigator ) {
import ( './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.

10000201000003e4000008004d3aea65db2aba6c-7000463
Auswählen einer App, für die die Datei freigegeben werden soll.
10000201000003e400000800d873c982e6d44c89-9083099
Die Datei wird an eine neue E-Mail in Google Mail Composer 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 = async ( ) => {
const properties = [ 'name' ] ;
const options = { multiple : true } ;
versuche {
Rückkehr warten Navigator . Kontakte . auswählen ( Eigenschaften , Optionen ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

Und jetzt haben Sie wahrscheinlich das Muster gelernt:
Ich lade die Datei nur, wenn die API tatsächlich unterstützt wird.

if ( 'Kontakte' im Navigator ) {
import ( './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.

10000201000003e400000800ad376e3b4b3386c6-2969667
Auswählen von zwei Namen mit der Kontaktauswahl aus dem Adressbuch.
1000000000000438000008ac945569e52ce934fa-7828050
Die beiden Namen werden dann auf die 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 copy = async ( blob ) => {
versuche {
warte auf navigator . Zwischenablage . schreiben ( [
neues ClipboardItem ( {
[ Blob . Typ ] : Blob ,
} ) ,
] ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 paste = async ( ) => {
versuche {
const clipboardItems = warte auf Navigator . Zwischenablage . read ( ) ;
for ( const clipboardItem von clipboardItems ) {
versuche {
for ( const type of clipboardItem . types ) {
const blob = warte auf clipboardItem . getType ( Typ ) ;
Rückkehr blob;
}}
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
}}
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

Und es ist mittlerweile fast unnötig zu sagen. Ich mache das nur bei der Unterstützung von Browsern.

if ( 'Zwischenablage' im Navigator && 'Schreiben' im Navigator . Zwischenablage ) {
import ( './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.

10000201000009c4000006a2fe8ceb5ee2fb3f83-8002472
Die Eingabeaufforderung für die Zwischenablage-Berechtigung.

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.

10000201000009c4000005a941a3287f1a5052a8-7523602
Ein Bild, das in die macOS Preview App eingefügt wurde.

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.

let 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.

if ( 'setAppBadge' im Navigator ) {
import ( './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.

10000201000009c4000005dbe9bf427abd63947a-3978772
Zeichnen Sie die Zahlen von 1 bis 7 mit sieben Stiftstrichen.
10000201000002e6000001c0855aa2df1e30228c-3334591
Der Zähler für Stiftstriche wird in Form des App-Symbolabzeichens angezeigt.

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 = async ( ) => {
const registrierung = warte auf navigator . serviceWorker . bereit ;
versuche {
Registrierung . periodicSync . register ( 'Bild des Tages synchronisieren' , {
minInterval : 24 * 60 * 60 * 1000 ,
} ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 ) => {
if ( syncEvent . tag === 'Bild des Tages synchronisieren' ) {
syncEvent . waitUntil (
( async ( ) => {
const blob = warte auf getImageOfTheDay ( ) ;
const clients = warte auf dich . Kunden . matchAll ( ) ;
Kunden . forEach ( ( client ) => {
Client . postMessage ( {
Bild : Blob ,
} ) ;
} ) ;
} ) ( )
) ;
}}
} ) ;

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 registrierung = warte auf navigator . serviceWorker . bereit ;
if ( Registrierung && 'periodicSync' bei der Registrierung ) {
import ( './periodic_background_sync.mjs' ) ;
}}


if ( 'periodicSync' in 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.

10000201000009c4000005e0b042853d0e77c224-9063496
Drücken Sie die Hintergrund Schaltfläche zeigt das Bild des Tages an.

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 ( ) ;
if ( targetDate ) {
const registrierung = warte auf navigator . serviceWorker . bereit ;
Registrierung . showNotification ( 'Erinnerung' , {
Tag : 'Erinnerung' ,
body : "Es ist Zeit, deine Grußkarte fertig zu stellen!" ,
showTrigger : neuer TimestampTrigger ( targetDate ) ,
} ) ;
}}

Wie bei allem anderen, was ich bisher gezeigt habe, ist dies eine progressive Verbesserung.
Der Code wird also nur bedingt geladen.

if ( 'Benachrichtigung' im Fenster && 'showTrigger' in Benachrichtigung. Prototyp) {
import ( './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.

10000201000009c4000005db0d42f493acfd1b53-3464336
Planen einer lokalen Benachrichtigung, die daran erinnert werden soll, eine Grußkarte fertigzustellen.

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.

10000201000009c4000005e0b042853d0e77c225-6170541
Die ausgelöste Benachrichtigung wird im macOS Notification Center angezeigt.

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.

let wakeLock = null ;
const requestWakeLock = async ( ) => {
wakeLock = warte auf Navigator . wakeLock . Anfrage ( 'Bildschirm' ) ;
wakeLock . addEventListener ( 'release' , ( ) => {
Konsole . log ( 'Wake Lock wurde freigegeben' ) ;
} ) ;
Konsole . log ( 'Wake Lock ist aktiv' ) ;
} ;

const handleVisibilityChange = ( ) => {
if ( wakeLock ! == null && document . sichtbarkeitsstatus === 'sichtbar' ) {
requestWakeLock ( ) ;
}}
} ;

Dokument . addEventListener ( 'Sichtbarkeitsänderung' , handleVisibilityChange ) ;
Dokument . addEventListener ( 'fullscreenchange' , handleVisibilityChange ) ;

Ja, dies ist eine progressive Verbesserung, daher muss ich sie nur laden, wenn der Browser
unterstützt die API.

if ( 'wakeLock' im Navigator && 'request' im Navigator . wakeLock ) {
import ( './wake_lock.mjs' ) ;
}}

In Fugu Greetings gibt es eine Schlaflosigkeit Kontrollkästchen, das, wenn aktiviert, die
Bildschirm wach.

10000201000009c4000005dbcd9d10dd0a745315-7387536
Das Schlaflosigkeit Kontrollkästchen hält App 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 = neuer IdleDetector ( ) ;
idleDetector . addEventListener ( 'change' , ( ) => {
const userState = idleDetector . userState ;
const screenState = idleDetector . screenState ;
Konsole . log ( `Leerlaufänderung . $ userState {}, {screenState $}`);
if ( userState === 'idle' ) {
clearCanvas ( ) ;
}}
} ) ;

Warten Sie auf idleDetector. start ( {
Schwelle : 60000 ,
Signal ,
} ) ;

Und wie immer lade ich diesen Code nur, wenn der Browser ihn unterstützt.

if ( 'IdleDetector' im Fenster ) {
import ( './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.

10000201000009c4000005dbb930b1d3f8f5d1da-7386592
Wenn der Flüchtig Das Kontrollkästchen ist aktiviert und der Benutzer war zu lange inaktiv. Die Zeichenfläche wird gelöscht.

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.

10000201000009c4000006e8d776365d6b538c9a-8214623
Auf der Registerkarte "Chrome DevTools-Netzwerk" werden nur Anforderungen für Dateien mit Code angezeigt, die vom aktuellen Browser unterstützt werden.

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.

android-2817055
Fugu Grüße läuft auf Android Chrome.
Safari-1435212
Fugu Grüße läuft auf Desktop Safari.
Chrom-9897882
Fugu Grüße läuft auf Desktop Chrome.

Wenn Sie an der interessiert sind Fugu Grüße App,
geh finden und Gabel es auf GitHub.

10000201000009c4000005fb1ef077cdf01b8588-2947610
Fugu Grüße App 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.

Aufbau für moderne Browser und schrittweise Verbesserung wie im Jahr 2003


Aktualisiert

Erscheint in:
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.

100002010000053c000003e8b978fe17e590bc9a-2242580
Folie: Inklusives Webdesign für die Zukunft mit progressiver Verbesserung.
(Quelle)

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.

igraal_de-de
10000000000009c40000039ef0a6fe5c50e42dea-1991285
Die Browser-Support-Tabelle für ECMAScript 2015 (ES6). ((Quelle)

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.

10000000000009c400000304a19ef0ff1d72987d-1299321
Die Browser-Supporttabelle für Async-Funktionen. ((Quelle)

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 = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
console.log(0 ?? 42);

1000020100000640000003e810e16d93c747b2d5-1385902
Das Gras ist grün, wenn es um die wichtigsten JavaScript-Funktionen geht.
(Microsoft-Produkt-Screenshot, verwendet mit
Genehmigung.)

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.

10000201000009c4000006a2f58b840608cea761-4971462
Das Fugu Grüße Beispiel App.

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 = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};

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 (blob) => {
const a = Dokument . createElement ( 'a' ) ;
a . download = 'fugu-greeting.png' ;
a . href = URL . createObjectURL ( Blob ) ;
a . addEventListener ( 'click' , ( e ) => {
setTimeout ( ( ) => URL . revokeObjectURL ( a . href ) , 30 * 1000 ) ;
} ) ;
a . click ( ) ;
} ;

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 = ( ) => {
if ( 'ChooseFileSystemEntries' im Fenster ) {
Versprich es mir . alle ( [
import ( './import_image.mjs' ) ,
import ( './export_image.mjs' ) ,
] ) ;
} else {
Versprich es mir . alle ( [
import ( './import_image_legacy.mjs' ) ,
import ( './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.

100002010000058c000000ca65613fec1d7fb3e2-1128402
Registerkarte "Netzwerk" von Safari Web Inspector.
10000201000005800000012430b7b8786bf315dd-5981940
Registerkarte "Netzwerk" der Firefox Developer Tools.

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.

10000201000006fc0000021ad16a28ba8f5cbf1a-3614115
Registerkarte "Chrome DevTools-Netzwerk".

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 = async ( ) => {
versuche {
const handle = Wartefenster . selectFileSystemEntries ( {
akzeptiert : [
{
Beschreibung : 'Bilddateien' ,
mimeTypes : [ 'image / *' ] ,
Erweiterungen : [ 'jpg' , 'jpeg' , 'png' , 'webp' , 'svg' ] ,
} ,
] ,
} ) ;
Rückgabegriff . getFile ( ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 (blob) => {
versuche {
const handle = Wartefenster . selectFileSystemEntries ( {
Typ : 'Datei speichern' ,
akzeptiert : [
{
Beschreibung : 'Bilddatei' ,
Erweiterungen : [ 'png' ] ,
mimeTypes : [ 'image / png' ] ,
} ,
] ,
} ) ;
const writable = warte auf handle . createWritable ( ) ;
warte beschreibbar . schreiben ( Blob ) ;
warte beschreibbar . close ( ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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.

10000201000009c4000005db39851711e3cb3bf0-1180658
Der Dialog zum Öffnen der Datei.
10000201000009c4000005db01941257d7be6a85-4907083
Das importierte Bild.
10000201000009c4000005dbcbe1b58ec828bb29-9444761
Speichern des geänderten Bildes in einer neuen Datei.

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.

1000020100000356000001c434f5dd5d64721768-4082576
Web Share API auf Desktop Safari unter MacOS.

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.

versuche {
warte auf navigator . teilen ( {
Titel : 'Schauen Sie sich diesen Artikel an:' ,
Text : ` " $ { document . title } "von @tomayac: ` ,
URL : Dokument . querySelector ( 'link [rel = canonical]' ) . href ,
} ) ;
} catch ( err ) {
Konsole . warn ( err . name , err . message ) ;
}}

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 share = async ( Titel , Text , Blob ) => {
const data = {
Dateien : [
neue Datei ( [ blob ] , 'fugu-greeting.png' , {
Typ : Blob . Typ ,
} ) ,
] ,
Titel : Titel ,
Text : Text ,
} ;
versuche {
if ( ! ( navigator . canShare ( data ) ) ) {
throw new Error ( "Daten können nicht teilen.", Daten);
}}
warte auf navigator . teilen ( Daten ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 = ( ) => {
if ( 'share' im Navigator && 'canShare' im Navigator ) {
import ( './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.

10000201000003e4000008004d3aea65db2aba6c-7000463
Auswählen einer App, für die die Datei freigegeben werden soll.
10000201000003e400000800d873c982e6d44c89-9083099
Die Datei wird an eine neue E-Mail in Google Mail Composer 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 = async ( ) => {
const properties = [ 'name' ] ;
const options = { multiple : true } ;
versuche {
Rückkehr warten Navigator . Kontakte . auswählen ( Eigenschaften , Optionen ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

Und jetzt haben Sie wahrscheinlich das Muster gelernt:
Ich lade die Datei nur, wenn die API tatsächlich unterstützt wird.

if ( 'Kontakte' im Navigator ) {
import ( './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.

10000201000003e400000800ad376e3b4b3386c6-2969667
Auswählen von zwei Namen mit der Kontaktauswahl aus dem Adressbuch.
1000000000000438000008ac945569e52ce934fa-7828050
Die beiden Namen werden dann auf die 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 copy = async ( blob ) => {
versuche {
warte auf navigator . Zwischenablage . schreiben ( [
neues ClipboardItem ( {
[ Blob . Typ ] : Blob ,
} ) ,
] ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 paste = async ( ) => {
versuche {
const clipboardItems = warte auf Navigator . Zwischenablage . read ( ) ;
for ( const clipboardItem von clipboardItems ) {
versuche {
for ( const type of clipboardItem . types ) {
const blob = warte auf clipboardItem . getType ( Typ ) ;
Rückkehr blob;
}}
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
}}
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

Und es ist mittlerweile fast unnötig zu sagen. Ich mache das nur bei der Unterstützung von Browsern.

if ( 'Zwischenablage' im Navigator && 'Schreiben' im Navigator . Zwischenablage ) {
import ( './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.

10000201000009c4000006a2fe8ceb5ee2fb3f83-8002472
Die Eingabeaufforderung für die Zwischenablage-Berechtigung.

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.

10000201000009c4000005a941a3287f1a5052a8-7523602
Ein Bild, das in die macOS Preview App eingefügt wurde.

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.

let 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.

if ( 'setAppBadge' im Navigator ) {
import ( './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.

10000201000009c4000005dbe9bf427abd63947a-3978772
Zeichnen Sie die Zahlen von 1 bis 7 mit sieben Stiftstrichen.
10000201000002e6000001c0855aa2df1e30228c-3334591
Der Zähler für Stiftstriche wird in Form des App-Symbolabzeichens angezeigt.

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 = async ( ) => {
const registrierung = warte auf navigator . serviceWorker . bereit ;
versuche {
Registrierung . periodicSync . register ( 'Bild des Tages synchronisieren' , {
minInterval : 24 * 60 * 60 * 1000 ,
} ) ;
} catch ( err ) {
Konsole . Fehler (. err Name, err - Nachricht.);
}}
} ;

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 ) => {
if ( syncEvent . tag === 'Bild des Tages synchronisieren' ) {
syncEvent . waitUntil (
( async ( ) => {
const blob = warte auf getImageOfTheDay ( ) ;
const clients = warte auf dich . Kunden . matchAll ( ) ;
Kunden . forEach ( ( client ) => {
Client . postMessage ( {
Bild : Blob ,
} ) ;
} ) ;
} ) ( )
) ;
}}
} ) ;

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 registrierung = warte auf navigator . serviceWorker . bereit ;
if ( Registrierung && 'periodicSync' bei der Registrierung ) {
import ( './periodic_background_sync.mjs' ) ;
}}


if ( 'periodicSync' in 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.

10000201000009c4000005e0b042853d0e77c224-9063496
Drücken Sie die Hintergrund Schaltfläche zeigt das Bild des Tages an.

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 ( ) ;
if ( targetDate ) {
const registrierung = warte auf navigator . serviceWorker . bereit ;
Registrierung . showNotification ( 'Erinnerung' , {
Tag : 'Erinnerung' ,
body : "Es ist Zeit, deine Grußkarte fertig zu stellen!" ,
showTrigger : neuer TimestampTrigger ( targetDate ) ,
} ) ;
}}

Wie bei allem anderen, was ich bisher gezeigt habe, ist dies eine progressive Verbesserung.
Der Code wird also nur bedingt geladen.

if ( 'Benachrichtigung' im Fenster && 'showTrigger' in Benachrichtigung. Prototyp) {
import ( './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.

10000201000009c4000005db0d42f493acfd1b53-3464336
Planen einer lokalen Benachrichtigung, die daran erinnert werden soll, eine Grußkarte fertigzustellen.

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.

10000201000009c4000005e0b042853d0e77c225-6170541
Die ausgelöste Benachrichtigung wird im macOS Notification Center angezeigt.

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.

let wakeLock = null ;
const requestWakeLock = async ( ) => {
wakeLock = warte auf Navigator . wakeLock . Anfrage ( 'Bildschirm' ) ;
wakeLock . addEventListener ( 'release' , ( ) => {
Konsole . log ( 'Wake Lock wurde freigegeben' ) ;
} ) ;
Konsole . log ( 'Wake Lock ist aktiv' ) ;
} ;

const handleVisibilityChange = ( ) => {
if ( wakeLock ! == null && document . sichtbarkeitsstatus === 'sichtbar' ) {
requestWakeLock ( ) ;
}}
} ;

Dokument . addEventListener ( 'Sichtbarkeitsänderung' , handleVisibilityChange ) ;
Dokument . addEventListener ( 'fullscreenchange' , handleVisibilityChange ) ;

Ja, dies ist eine progressive Verbesserung, daher muss ich sie nur laden, wenn der Browser
unterstützt die API.

if ( 'wakeLock' im Navigator && 'request' im Navigator . wakeLock ) {
import ( './wake_lock.mjs' ) ;
}}

In Fugu Greetings gibt es eine Schlaflosigkeit Kontrollkästchen, das, wenn aktiviert, die
Bildschirm wach.

10000201000009c4000005dbcd9d10dd0a745315-7387536
Das Schlaflosigkeit Kontrollkästchen hält App 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 = neuer IdleDetector ( ) ;
idleDetector . addEventListener ( 'change' , ( ) => {
const userState = idleDetector . userState ;
const screenState = idleDetector . screenState ;
Konsole . log ( `Leerlaufänderung . $ userState {}, {screenState $}`);
if ( userState === 'idle' ) {
clearCanvas ( ) ;
}}
} ) ;

Warten Sie auf idleDetector. start ( {
Schwelle : 60000 ,
Signal ,
} ) ;

Und wie immer lade ich diesen Code nur, wenn der Browser ihn unterstützt.

if ( 'IdleDetector' im Fenster ) {
import ( './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.

10000201000009c4000005dbb930b1d3f8f5d1da-7386592
Wenn der Flüchtig Das Kontrollkästchen ist aktiviert und der Benutzer war zu lange inaktiv. Die Zeichenfläche wird gelöscht.

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.

10000201000009c4000006e8d776365d6b538c9a-8214623
Auf der Registerkarte "Chrome DevTools-Netzwerk" werden nur Anforderungen für Dateien mit Code angezeigt, die vom aktuellen Browser unterstützt werden.

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.

android-2817055
Fugu Grüße läuft auf Android Chrome.
Safari-1435212
Fugu Grüße läuft auf Desktop Safari.
Chrom-5393316
Fugu Grüße läuft auf Desktop Chrome.

Wenn Sie an der interessiert sind Fugu Grüße App,
geh finden und Gabel es auf GitHub.

10000201000009c4000005fb1ef077cdf01b8588-2947610
Fugu Grüße App 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.

Error: Beachtung: Geschützter Inhalt.