Entwicklung für moderne Browser und schrittweise Verbesserungen wie im Jahr 2003
Im März 2003 haben Nick Finck und Steve Champeon verblüfft die Welt des Webdesigns mit dem Konzept der Progressive Verbesserung eine Strategie für das Webdesign, bei der der Schwerpunkt darauf liegt, dass grundlegende Webseiteninhalte zuerst geladen werden. Dann werden nach und nach differenziertere und technisch anspruchsvollen Präsentations- und Funktionsebenen. Im Jahr 2003 ging es bei Progressive Enhancement um die Nutzung der damaligen Zeit CSS-Funktionen, unaufdringliches JavaScript und sogar skalierbare Vektorgrafiken Bei Progressive Enhancement im Jahr 2020 und darüber hinaus geht es darum, modernen Browserfunktionen.
<ph type="x-smartling-placeholder">Modernes JavaScript
Apropos JavaScript, die Browserunterstützung für die neueste Hauptversion von ES 2015
Funktionen ist großartig.
Der neue Standard umfasst Promise, Module, Klassen, Vorlagenliterale, Pfeilfunktionen, let
und const
.
Standardparameter, Generatoren, die destruktive Zuweisung, Ruhe und Verteilung, Map
/Set
,
WeakMap
/WeakSet
und viele weitere.
Alle werden unterstützt.
Async-Funktionen, eine Funktion von ES 2017 und einer meiner persönlichen Favoriten,
können verwendet werden,
in allen gängigen Browsern.
Die Keywords async
und await
ermöglichen ein asynchrones, Promise-basiertes Verhalten
in einem saubereren Stil geschrieben werden, sodass keine Promise-Ketten explizit konfiguriert werden müssen.
2020 wurden neue Sprachen auf Spanisch hinzugefügt, zum Beispiel: optionale Verkettung und Nullish-Koalescing Support sehr schnell erreicht haben. Unten sehen Sie ein Codebeispiel. Was JavaScript-Kernfunktionen angeht, so könnte das Gras nicht viel umweltfreundlicher sein. ist heute.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
// Expected output: undefined
console.log(0 ?? 42);
// Expected output: 0
Die Beispiel-App: Fugu Greetings
Für diesen Artikel verwende ich eine einfache PWA namens Fugu-Grüße (GitHub) Der Name dieser App ist nur ein kleiner Pluspunkt für Project Fugu 🐡 – damit das Web im Web die Leistungsfähigkeit von Android-/iOS-/Desktop-Anwendungen. Weitere Informationen zum Projekt finden Sie in der Landingpage.
Mit der Zeichen-App Fugu Greetings können Sie virtuelle Grußkarten erstellen und an deine Liebsten zu senden. Es zeigt beispielhaft Kernkonzepte von PWAs Es ist zuverlässig und vollständig offline aktiviert sind. Netzwerk haben, können Sie es weiterhin verwenden. Außerdem ist sie installierbar. zum Startbildschirm eines Geräts und ist nahtlos in das Betriebssystem integriert. als eigenständige Anwendung.
<ph type="x-smartling-placeholder">Progressive Enhancement
Jetzt ist es an der Zeit, über Progressive Verbesserung zu sprechen. Das Glossar der MDN-Webdokumente beschreibt Konzept:
Progressive Enhancement ist eine Designphilosophie, die als Basis für wesentlichen Inhalten und Funktionen möglichst vielen Nutzenden zugänglich machen, während die bestmögliche Erfahrung nur den Nutzern mit den modernsten Browser, die den gesamten erforderlichen Code ausführen können.
Funktionserkennung wird im Allgemeinen verwendet, um zu bestimmen, ob Browser modernere Funktionen, während Polyfills werden häufig verwendet, um fehlende Funktionen mit JavaScript hinzuzufügen.
[…]
Progressive Enhancement ist eine nützliche Technik, mit der sich Webentwickler darauf konzentrieren können, die bestmöglichen Websites zu entwickeln und diese gleichzeitig für mehrere unbekannte User-Agents. Graceful Degradation sind verwandt, aber nicht dasselbe und wird oft als entgegengesetzte Richtung betrachtet zu Progressive Enhancement. Tatsächlich sind beide Ansätze sinnvoll und können sich oft gegenseitig ergänzen.
MDN-Beitragende
Jede Grußkarte von Grund auf neu zu erstellen, kann sehr mühsam sein.
Wie wäre es also mit einer Funktion, mit der Nutzer Bilder importieren und direkt loslegen können?
Bei der herkömmlichen Herangehensweise
<input type=file>
-Element zu verwenden.
Zuerst erstellen Sie das Element, legen type
auf 'file'
fest und fügen dem Attribut accept
MIME-Typen hinzu.
und dann programmatisch auf und auf Veränderungen warten.
Wenn Sie ein Bild auswählen, wird es direkt in den Canvas 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 eine Importfunktion vorhanden ist, sollte wahrscheinlich auch eine Exportfunktion vorhanden sein.
damit Nutzer ihre Grußkarten lokal speichern können.
Herkömmliche Methoden zum Speichern von Dateien sind Ankerlinks.
mit download
und mit einer Blob-URL als href
.
Außerdem würden Sie programmatisch auf um den Download auszulösen,
Vergessen Sie nicht, die Blob-Objekt-URL zu widerrufen, um Speicherlecks zu vermeiden.
const exportImage = async (blob) => {
const a = document.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 mal. Sie haben die Datei noch nicht "heruntergeladen", eine Grußkarte haben, "gespeichert" . Anstatt eine Schaltfläche zum Speichern in dem Sie auswählen können, wo die Datei gespeichert werden soll, Der Browser hat die Grußkarte direkt und ohne Interaktion des Nutzers heruntergeladen. und direkt im Ordner "Downloads" abgelegt. 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, sie bearbeiten und dann die Änderungen speichern könnten, entweder in einer neuen Datei oder in der ursprünglichen Datei, die Sie zuvor geöffnet hatten? Es stellt sich heraus, dass es eine gibt. Die File System Access API können Sie Dateien öffnen und erstellen sowie ändern und speichern .
Wie kann ich eine Feature-Erkennung für eine API durchführen?
Die File System Access API stellt die neue Methode window.chooseFileSystemEntries()
zur Verfügung.
Daher muss ich abhängig davon, ob diese Methode verfügbar ist, verschiedene Import- und Exportmodule bedingt laden. Wie das geht, sehen Sie im Folgenden.
const loadImportAndExport = () => {
if ('chooseFileSystemEntries' in window) {
Promise.all([
import('./import_image.mjs'),
import('./export_image.mjs'),
]);
} else {
Promise.all([
import('./import_image_legacy.mjs'),
import('./export_image_legacy.mjs'),
]);
}
};
Bevor wir uns mit den Details der File System Access API beschäftigen, möchte ich hier kurz das Progressive-Enhancement-Muster hervorheben. In Browsern, die die File System Access API derzeit nicht unterstützen, lade ich die alten Skripts. Unten sehen Sie die Netzwerk-Tabs von Firefox und Safari.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">In Chrome, einem Browser, der die API unterstützt, werden jedoch nur die neuen Skripts geladen.
Dies wird elegant möglich dank
dynamisches import()
, das alle modernen Browser
Support.
Wie ich bereits sagte, ist das Gras heutzutage ziemlich grün.
Die File System Access API
Nachdem wir dieses Problem behandelt haben, sehen wir uns nun die tatsächliche Implementierung basierend auf dem File System Access API an.
Zum Importieren eines Bildes rufe ich window.chooseFileSystemEntries()
auf
und übergeben eine accepts
-Eigenschaft,
wo ich Bilddateien angeben möchte.
Es werden sowohl Dateierweiterungen als auch MIME-Typen unterstützt.
Dies führt zu einem Datei-Handle, aus dem ich die eigentliche Datei abrufen kann, indem ich getFile()
aufrufe.
const importImage = async () => {
try {
const handle = await window.chooseFileSystemEntries({
accepts: [
{
description: 'Image files',
mimeTypes: ['image/*'],
extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
Der Export eines Images ist fast identisch, diesmal jedoch
Ich muss den Typparameter 'save-file'
an die Methode chooseFileSystemEntries()
übergeben.
Daraufhin wird ein Dialogfeld zum Speichern von Dateien angezeigt.
Bei geöffneter Datei war dies nicht erforderlich, da 'open-file'
die Standardeinstellung ist.
Ich habe den Parameter accepts
ähnlich wie zuvor festgelegt, aber diesmal nur auf PNG-Bilder.
Ich erhalte wieder ein Datei-Handle, aber statt die Datei abzurufen,
dieses Mal erstelle ich einen beschreibbaren Stream, indem ich createWritable()
aufrufe.
Als Nächstes schreibe ich den Blob, das Bild meiner Grußkarte, in die Datei.
Schließlich schließe ich den beschreibbaren Stream.
Alles kann immer ausfallen: Auf dem Laufwerk ist möglicherweise nicht genügend Speicherplatz,
Möglicherweise liegt ein Schreib- oder Lesefehler vor oder der Nutzer schließt den Dateidialog einfach ab.
Deshalb schließe ich die Aufrufe immer in eine try...catch
-Anweisung ein.
const exportImage = async (blob) => {
try {
const handle = await window.chooseFileSystemEntries({
type: 'save-file',
accepts: [
{
description: 'Image file',
extensions: ['png'],
mimeTypes: ['image/png'],
},
],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
};
Bei der Verwendung von Progressive Enhancement mit der File System Access API Ich kann eine Datei wie zuvor öffnen. Die importierte Datei wird direkt auf dem Canvas 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 unbegrenzte Zeit aufbewahrt werden.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Web Share und Web Share Target APIs
Außer für die Ewigkeit möchte ich meine Grußkarte vielleicht auch mit anderen teilen. Das ist etwas, das die Web Share API und Web Share Target API. Mobilgeräte und seit Kurzem Desktop-Betriebssysteme haben integrierte Freigabefunktionen. Mechanismen. Unten sehen Sie zum Beispiel das Share Sheet von Safari für macOS, das von einem Artikel über meinen Blog Durch Klicken auf die Schaltfläche Artikel teilen kannst du einen Link zu dem Artikel mit Freunden teilen: über die macOS Messages App.
<ph type="x-smartling-placeholder">Der Code dafür ist ziemlich einfach. Ich rufe navigator.share()
an und
ein optionales title
-, text
- und url
-Element in einem Objekt übergeben.
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 Funktionen zur Dateifreigabe hinzugefügt hat.
try {
await navigator.share({
title: 'Check out this article:',
text: `"${document.title}" by @tomayac:`,
url: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.name, err.message);
}
Ich zeige Ihnen, wie das mit der Fugu-Grußkartenanwendung funktioniert.
Zuerst muss ich ein data
-Objekt mit einem files
-Array vorbereiten, das aus einem Blob besteht, und dann
title
und text
. Als Nächstes verwende ich die neue navigator.canShare()
-Methode, die
was der Name schon sagt:
Sie teilt mir mit, ob das data
-Objekt, das ich freigeben möchte, technisch vom Browser geteilt werden kann.
Wenn navigator.canShare()
mir mitteilt, dass die Daten geteilt werden können, bin ich bereit
rufen Sie navigator.share()
wie zuvor auf.
Weil alles fehlschlagen kann, verwende ich wieder einen try...catch
-Block.
const share = async (title, text, blob) => {
const data = {
files: [
new File([blob], 'fugu-greeting.png', {
type: blob.type,
}),
],
title: title,
text: text,
};
try {
if (!(navigator.canShare(data))) {
throw new Error("Can't share data.", data);
}
await navigator.share(data);
} catch (err) {
console.error(err.name, err.message);
}
};
Wie zuvor nutze ich Progressive Enhancement.
Wenn sowohl 'share'
als auch 'canShare'
im Objekt navigator
vorhanden sind, gehe ich nur vor und
share.mjs
über dynamisches import()
laden.
In Browsern wie Safari auf dem Mobilgerät, die nur eine der beiden Bedingungen erfüllen, werde ich nicht
die Funktionalität kennen.
const loadShare = () => {
if ('share' in navigator && 'canShare' in navigator) {
import('./share.mjs');
}
};
Wenn ich in Fugu Begrüßungen in einem unterstützten Browser wie Chrome unter Android auf die Schaltfläche Teilen tippe, wird das integrierte Tabellenblatt zum Teilen geöffnet. Ich kann zum Beispiel Google Mail auswählen und das Widget zur Erstellung von E-Mails erscheint Bild angehängt.
Die Contact Picker API
Als Nächstes möchte ich über Kontakte sprechen, also über das Adressbuch eines Geräts. oder Kontaktmanager-App. Es ist nicht immer einfach, Grußkarten richtig zu schreiben. auf den Namen einer Person. Ich habe zum Beispiel einen Freund Sergey, der seinen Namen lieber in kyrillischen Buchstaben schreiben möchte. Ich bin mit einer deutschen QWERTZ-Tastatur verwendet und wissen nicht, wie man den Namen eingibt. Dieses Problem kann mit der Contact Picker API behoben werden. Da ich eine Person in der Kontakte App auf meinem Smartphone gespeichert habe, kann ich über die Contacts Picker API auf meine Kontakte im Web zugreifen.
Zuerst muss ich die Liste der Properties angeben, auf die ich zugreifen möchte.
In diesem Fall möchte ich nur die Namen,
aber für andere Anwendungsfälle sind Telefonnummern, E-Mail-Adressen, Avatare
Symbole oder physische Adressen.
Als Nächstes konfiguriere ich ein options
-Objekt und setze multiple
auf true
, damit ich mehr auswählen kann
als ein Eintrag.
Schließlich kann ich navigator.contacts.select()
aufrufen, wodurch die gewünschten Eigenschaften zurückgegeben werden.
für die vom Nutzer ausgewählten Kontakte.
const getContacts = async () => {
const properties = ['name'];
const options = { multiple: true };
try {
return await navigator.contacts.select(properties, options);
} catch (err) {
console.error(err.name, err.message);
}
};
Und inzwischen haben Sie das Muster wahrscheinlich kennengelernt: Ich lade die Datei nur, wenn die API tatsächlich unterstützt wird.
if ('contacts' in navigator) {
import('./contacts.mjs');
}
Wenn ich in der Fugu-Begrüßung auf die Schaltfläche Kontakte tippe und meine zwei besten Freunde auswähle, Kерргей 電кайлокиfenster БриLIMIT und 劳伦斯·爱德华·"拉里"·佩奇, können Sie sehen, wie die nur die Namen der Kontakte, nicht jedoch E-Mail-Adressen oder andere Informationen wie Telefonnummern. Ihre Namen werden dann auf meine Grußkarte gezeichnet.
Die Asynchronous Clipboard API
Als Nächstes folgt das Kopieren und Einfügen. Eine unserer Lieblingsbeschäftigungen als Softwareentwickler ist Kopieren und Einfügen. Als Grußkartenautor möchte ich dasselbe manchmal tun. Ich möchte entweder ein Bild in eine Grußkarte einfügen, an der ich arbeite, oder kopiere meine Grußkarte, damit ich sie über woanders hin. Async Clipboard API unterstützt sowohl Text als auch Bilder. Ich erkläre Ihnen gern, wie ich die Unterstützung für Kopieren und Einfügen auf der Fugu-Website hinzugefügt habe. Begrüßungs-App.
Um etwas in die Zwischenablage des Systems zu kopieren, muss ich darin schreiben.
Bei der Methode navigator.clipboard.write()
wird ein Array von Elementen in der Zwischenablage als
.
Jedes Element in der Zwischenablage ist im Wesentlichen ein Objekt mit einem Blob als Wert und der Typ des Blobs.
als Schlüssel ein.
const copy = async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
console.error(err.name, err.message);
}
};
Zum Einfügen muss ich die Elemente in der Zwischenablage durchgehen, die ich durch Aufruf von
navigator.clipboard.read()
Das liegt daran, dass sich in der Zwischenablage möglicherweise mehrere Elemente
verschiedene Darstellungen.
Jedes Element in der Zwischenablage hat ein types
-Feld mit den MIME-Typen der verfügbaren
Ressourcen.
Ich rufe die getType()
-Methode des Zwischenablage-Elements auf und übermittle den
MIME-Typ, den ich zuvor abgerufen habe.
const paste = async () => {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
return blob;
}
} catch (err) {
console.error(err.name, err.message);
}
}
} catch (err) {
console.error(err.name, err.message);
}
};
Das ist mittlerweile fast unnötig. Ich mache das nur mit unterstützten Browsern.
if ('clipboard' in navigator && 'write' in navigator.clipboard) {
import('./clipboard.mjs');
}
Wie funktioniert das in der Praxis? Ich habe ein Bild in der macOS Preview App geöffnet und in die Zwischenablage kopieren. Wenn ich auf Einfügen klicke, werden Sie in der Fugu Begrüßungen App gefragt, ob ich der App erlauben möchte, Text und Bilder in der Zwischenablage abzurufen.
<ph type="x-smartling-placeholder">Nachdem Sie die Genehmigung akzeptiert haben, wird das Bild in die Anwendung eingefügt. Andersherum funktioniert es auch. Ich kopiere eine Grußkarte in die Zwischenablage. Wenn ich dann die Vorschau öffne und auf Datei und dann auf Neu aus Zwischenablage klicke, wird die Grußkarte in ein neues unbenanntes Bild eingefügt.
<ph type="x-smartling-placeholder">Die Badging API
Eine weitere nützliche API ist die Badging API.
Als installierbare PWA hat Fugu Greetings natürlich ein App-Symbol
die Nutzer auf dem App-Dock oder auf dem Startbildschirm platzieren können.
Eine unterhaltsame und einfache Möglichkeit, die API zu demonstrieren, besteht darin, sie in Fugu-Grüßen zu verwenden.
als Stiftstrichzähler.
Ich habe einen Event-Listener hinzugefügt, der den Stiftzähler erhöht, wenn das pointerdown
-Ereignis eintritt
und legt dann das aktualisierte Symbol fest.
Sobald der Canvas geleert wird, wird der Zähler zurückgesetzt und das Logo entfernt.
let strokes = 0;
canvas.addEventListener('pointerdown', () => {
navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigator.setAppBadge(strokes);
});
Bei dieser Funktion handelt es sich um eine progressive Verbesserung, die Ladelogik ist also wie gewohnt.
if ('setAppBadge' in navigator) {
import('./badge.mjs');
}
In diesem Beispiel habe ich mit einem Stift die Zahlen von eins bis sieben gezeichnet. pro Nummer. Der Badge-Zähler auf dem Symbol steht jetzt bei sieben.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Die Periodic Background Sync API
Du möchtest jeden Tag mit etwas Neuem beginnen? Eine tolle Funktion der Fugu Begrüßungs-App ist, dass sie dich jeden Morgen inspiriert. mit einem neuen Hintergrundbild, um mit Ihrer Grußkarte zu beginnen. Die App verwendet die Periodic Background Sync API. um dies zu erreichen.
Der erste Schritt besteht darin, ein regelmäßiges Synchronisierungsereignis in der Service Worker-Registrierung zu registrieren.
Wartet auf das Synchronisierungs-Tag 'image-of-the-day'
Das Intervall beträgt mindestens einen Tag.
sodass der Nutzer alle 24 Stunden ein neues Hintergrundbild erhalten kann.
const registerPeriodicBackgroundSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
registration.periodicSync.register('image-of-the-day-sync', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.error(err.name, err.message);
}
};
Der zweite Schritt besteht darin, im Service Worker auf das Ereignis periodicsync
zu warten.
Wenn das Ereignis-Tag 'image-of-the-day'
ist, also das zuvor registrierte Tag,
Das Bild des Tages wird mit der Funktion getImageOfTheDay()
abgerufen.
Das Ergebnis wird an alle Kunden weitergegeben, sodass sie ihre Canvases aktualisieren und
Caches.
self.addEventListener('periodicsync', (syncEvent) => {
if (syncEvent.tag === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(async () => {
const blob = await getImageOfTheDay();
const clients = await self.clients.matchAll();
clients.forEach((client) => {
client.postMessage({
image: blob,
});
});
})()
);
}
});
Auch hier handelt es sich um eine progressive Verbesserung, d. h., der Code wird nur geladen,
Die API wird vom Browser unterstützt.
Dies gilt sowohl für den Clientcode als auch für den Service Worker-Code.
In nicht unterstützten Browsern wird keiner von beiden geladen.
Im Service Worker anstelle eines dynamischen import()
-Objekts
(wird in einem Service Worker-Kontext nicht unterstützt)
noch)
Ich nutze den klassischen
importScripts()
// In the client:
const registration = await navigator.serviceWorker.ready;
if (registration && 'periodicSync' in registration) {
import('./periodic_background_sync.mjs');
}
// In the service worker:
if ('periodicSync' in self.registration) {
importScripts('./image_of_the_day.mjs');
}
Wenn Sie in Fugu entsprechende Benachrichtigungen drücken, wird das Grußkartenbild des Tages angezeigt, wenn Sie auf die Schaltfläche Hintergrund klicken. die täglich über die Periodic Background Sync API aktualisiert wird.
<ph type="x-smartling-placeholder">Notification Triggers API
Manchmal braucht man auch bei viel Inspiration einen Anstupser, um eine begonnene Begrüßung fertigzustellen . Diese Funktion wird durch die Notification Triggers API aktiviert. Als Nutzer kann ich eine Uhrzeit eingeben, zu der ich daran erinnert werden möchte, meine Grußkarte fertigzustellen. Zu diesem Zeitpunkt werde ich eine Benachrichtigung erhalten, dass meine Grußkarte bereitsteht.
Nach der Aufforderung zur Zielzeit
Die Anwendung plant die Benachrichtigung mit einem showTrigger
.
Dies kann ein TimestampTrigger
mit dem zuvor ausgewählten Zieldatum sein.
Die Erinnerungsbenachrichtigung wird lokal ausgelöst und erfordert weder ein Netzwerk noch eine Serverseite.
const targetDate = promptTargetDate();
if (targetDate) {
const registration = await navigator.serviceWorker.ready;
registration.showNotification('Reminder', {
tag: 'reminder',
body: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
Wie bei allem, was ich bisher gezeigt habe, ist dies eine progressive Verbesserung, sodass der Code nur bedingt geladen wird.
if ('Notification' in window && 'showTrigger' in Notification.prototype) {
import('./notification_triggers.mjs');
}
Wenn ich das Kästchen Erinnerung in Fugu Begrüßungen auswähle, werden Sie gefragt, wenn ich daran erinnert werden möchte, meine Grußkarte fertigzustellen.
<ph type="x-smartling-placeholder">Wenn eine geplante Benachrichtigung in Fugu-Begrüßungen ausgelöst wird, wie jede andere Benachrichtigung angezeigt, aber wie bereits erwähnt, war keine Netzwerkverbindung erforderlich.
<ph type="x-smartling-placeholder">Die Wake Lock API
Außerdem möchte ich die Wake Lock API einbeziehen. Manchmal musst du nur lange genug auf den Bildschirm starren, bis du dich inspiriert hast. küsst dich. Das Schlimmste, was dann passieren kann, ist, dass der Bildschirm ausgeschaltet wird. Die Wake Lock API kann dies verhindern.
Der erste Schritt besteht darin, mit navigator.wakelock.request method()
einen Wakelock zu erhalten.
Ich übergebe den String 'screen'
, um einen Display-Wakelock zu erhalten.
Dann füge ich einen Event-Listener hinzu, der informiert wird, wenn der Wakelock freigegeben wird.
Das kann beispielsweise passieren, wenn sich die Sichtbarkeit des Tabs ändert.
In diesem Fall kann ich den Wakelock neu anfordern, sobald der Tab wieder sichtbar wird.
let wakeLock = null;
const requestWakeLock = async () => {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
};
const handleVisibilityChange = () => {
if (wakeLock !== null && document.visibilityState === 'visible') {
requestWakeLock();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener('fullscreenchange', handleVisibilityChange);
Ja, es handelt sich um eine progressive Verbesserung, daher muss ich sie nur laden, wenn der Browser unterstützt die API.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
import('./wake_lock.mjs');
}
In Fugu Greetings gibt es ein Kästchen Insomnia (Schlaflosigkeit). Wenn dieses Kästchen angeklickt ist, Display aktiviert ist.
<ph type="x-smartling-placeholder">Die Idle Detection API
Auch wenn Sie stundenlang auf den Bildschirm starren, Es ist einfach nutzlos und Ihnen fällt nicht auf, was Sie mit der Grußkarte anfangen sollen. Mit der Idle Detection API kann die App die Inaktivitätszeit von Nutzern erkennen. Wenn der Nutzer zu lange inaktiv ist, wird die App auf den Ausgangszustand zurückgesetzt und löscht den Canvas. Diese API befindet sich derzeit hinter der Berechtigung für Benachrichtigungen da viele Anwendungsfälle der Inaktivitätserkennung Benachrichtigungen und Benachrichtigungen nur an Geräte senden, die der Nutzer gerade aktiv verwendet.
Nachdem ich sichergestellt habe, dass die Berechtigung zum Senden von Benachrichtigungen gewährt wurde, instanziiere ich die den Inaktivitätsdetektor. Ich registriere einen Event-Listener, der inaktive Änderungen überwacht, einschließlich Nutzer- und Bildschirmstatus. Der Nutzer kann aktiv oder inaktiv sein, und das Display kann entsperrt oder gesperrt werden. Ist der Nutzer inaktiv, wird der Canvas gelöscht. Ich lege für den Inaktivitätsdetektor einen Schwellenwert von 60 Sekunden fest.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.log(`Idle change: ${userState}, ${screenState}.`);
if (userState === 'idle') {
clearCanvas();
}
});
await idleDetector.start({
threshold: 60000,
signal,
});
Und wie immer lade ich diesen Code nur, wenn der Browser ihn unterstützt.
if ('IdleDetector' in window) {
import('./idle_detection.mjs');
}
In der Fugu Begrüßungen-App wird der Canvas gelöscht, wenn das Kästchen Sitzungsspezifisch überprüft und der Nutzer zu lange inaktiv ist.
<ph type="x-smartling-placeholder">Abschluss
Puh, was für ein Taxi. So viele APIs in nur einer Beispiel-App. Und denken Sie daran: Ich zwinge Nutzer nie dazu, die Downloadkosten zu bezahlen, für eine Funktion, die ihr Browser nicht unterstützt. Durch die Verwendung von Progressive Enhancement stelle ich sicher, dass nur der relevante Code geladen wird. Und da Anfragen bei HTTP/2 günstig sind, sollte dieses Muster für viele Anwendungen, Allerdings sollten Sie einen Bundler für sehr große Apps in Betracht ziehen.
<ph type="x-smartling-placeholder">Die App kann in jedem Browser ein wenig anders aussehen, da nicht alle Plattformen alle Funktionen unterstützen. aber die Hauptfunktion ist immer verfügbar und wird entsprechend den jeweiligen Browserfunktionen schrittweise verbessert. Diese Funktionen können sich auch in ein und demselben Browser ändern. je nachdem, ob die App als installierte App oder in einem Browsertab ausgeführt wird.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Wenn Sie sich für die App Fugu Greetings interessieren, auf GitHub.
<ph type="x-smartling-placeholder">Das Chromium-Team arbeitet intensiv daran, das Gras für moderne Fugu-APIs umweltfreundlicher zu gestalten. Indem ich bei der Entwicklung meiner App Progressive Enhancement anwende, Ich sorge dafür, dass alle eine gute und solide Grunderfahrung erhalten, aber Nutzer von Browsern, die mehr Webplattform-APIs unterstützen, profitieren von einer noch besseren Nutzererfahrung. Ich bin gespannt, wie Sie die progressive Verbesserung in Ihren Apps umsetzen.
Danksagungen
Ich bin Christian Liebel und
Hemanth HM, die beide an Fugu-Grüßen mitgewirkt haben.
Dieser Artikel wurde von Joe Medley geprüft und
Kayce Basques
Jake Archibald hat mir geholfen, die Situation
mit dynamischem import()
in einem Service Worker-Kontext.