Construire pour les navigateurs modernes et s'améliorer progressivement comme en 2003
Mise à jour
Applications Web progressives
De retour en mars 2003, Nick Fink et
Steve Champeon a stupéfié le monde de la conception Web
avec le concept de
amélioration progressive,
une stratégie de conception Web qui met l'accent sur le chargement du contenu principal de la page Web en premier,
et cela ajoute progressivement plus de nuances
et des couches de présentation et de fonctionnalités techniquement rigoureuses en plus du contenu.
Alors qu'en 2003, l'amélioration progressive consistait à utiliser - à l'époque - des
Fonctionnalités CSS, JavaScript discret et même simplement des graphiques vectoriels évolutifs.
L'amélioration progressive en 2020 et au-delà consiste à utiliser
capacités de navigateur modernes.
JavaScript moderne
En parlant de JavaScript, la situation de prise en charge du navigateur pour le dernier noyau JavaScript ES 2015
les fonctionnalités sont excellentes.
Le nouveau standard comprend des promesses, des modules, des classes, des modèles littéraux, des fonctions fléchées, laisser
et const
,
paramètres par défaut, générateurs, affectation de déstructuration, repos et diffusion, Carte
/Ensemble
,
WeakMap
/WeakSet
, et beaucoup plus.
Tous sont pris en charge.
Fonctions Async, une fonctionnalité ES 2017 et l'un de mes favoris personnels,
peut être utilisé
dans tous les principaux navigateurs.
le asynchrone
et attendre
les mots clés permettent un comportement asynchrone basé sur des promesses
à écrire dans un style plus propre, évitant d'avoir à configurer explicitement les chaînes de promesses.
Et même des ajouts linguistiques très récents pour l'ES 2020 comme
chaînage optionnel et
fusion nulle
ont atteint le support très rapidement. Vous pouvez voir un exemple de code ci-dessous.
En ce qui concerne les fonctionnalités JavaScript de base, l'herbe ne pourrait pas être beaucoup plus verte qu'elle
c'est aujourd'hui.
const adventurer = {
patate douce: 'Alice',
cat: {
patate douce: 'Dinah',
},
};
console.Journal(adventurer.dog?.patate douce);
console.Journal(0 ?? 42);
L'exemple d'application: Fugu Greetings
Pour cet article, je travaille avec une simple PWA, appelée
Salutations Fugu
(GitHub).
Le nom de cette application est une pointe du chapeau pour Project Fugu 🐡, un effort pour donner tout au Web
les pouvoirs des applications natives.
Vous pouvez en savoir plus sur le projet sur sa
page de destination.
Fugu Greetings est une application de dessin qui vous permet de créer des cartes de vœux virtuelles et d'envoyer
les à vos proches. Il illustre
Les concepts de base de PWA. C'est
fiable et entièrement hors ligne, donc même si vous ne le faites pas
avoir un réseau, vous pouvez toujours l'utiliser. Il est également installable
à l'écran d'accueil d'un appareil et s'intègre parfaitement au système d'exploitation
en tant qu'application autonome.
Amélioration progressive
Avec cela à l'écart, il est temps d'en parler amélioration progressive.
Glossaire MDN Web Docs vous définissez
le concept comme suit:
L'amélioration progressive est une philosophie de conception qui fournit une base de
contenu et fonctionnalités essentiels au plus grand nombre d'utilisateurs possible, tout en
offrir la meilleure expérience possible uniquement aux utilisateurs des plus modernes
navigateurs capables d'exécuter tout le code requis.Détection des fonctionnalités
est généralement utilisé pour déterminer si les navigateurs peuvent gérer des fonctionnalités plus modernes,
tandis que polyfills
sont souvent utilisés pour ajouter des fonctionnalités manquantes avec JavaScript.[…]
L'amélioration progressive est une technique utile qui permet aux développeurs Web de se concentrer
sur le développement des meilleurs sites Web possibles tout en faisant fonctionner ces sites Web
sur plusieurs agents utilisateurs inconnus.
Dégradation progressive
est lié, mais n'est pas la même chose et est souvent considéré comme allant dans la direction opposée
à l'amélioration progressive.
En réalité, les deux approches sont valables et peuvent souvent se compléter.
Contributeurs MDN
Commencer chaque carte de voeux à partir de zéro peut être vraiment fastidieux.
Alors pourquoi ne pas avoir une fonctionnalité qui permet aux utilisateurs d'importer une image, et de partir de là?
Avec une approche traditionnelle, vous auriez utilisé un
élément pour y arriver.
Tout d'abord, vous créez l'élément, définissez son taper
à 'déposer'
et ajoutez des types MIME au J'accepte
propriété,
puis "cliquez" dessus par programme et écoutez les changements.
Lorsque vous sélectionnez une image, elle est importée directement sur le canevas.
const importImage = asynchrone () => {
revenir new Promise((resolve) => {
const contribution = document.createElement('input');
contribution.taper = 'déposer';
contribution.J'accepte = 'image/*';
contribution.addEventListener('change', () => {
resolve(contribution.des dossiers[0]);
});
contribution.Cliquez sur();
});
};
Quand il y a un importer caractéristique, il devrait probablement y avoir un exportation fonctionnalité
afin que les utilisateurs puissent enregistrer leurs cartes de vœux localement.
La manière traditionnelle d'enregistrer des fichiers consiste à créer un lien d'ancrage
avec un Télécharger
attribut et avec une URL blob comme son href
.
Vous devez également "cliquer" par programmation dessus pour déclencher le téléchargement,
et, pour éviter les fuites de mémoire, n'oubliez pas de révoquer l'URL de l'objet blob.
const exportImage = asynchrone (goutte) => {
const à = document.createElement('a');
à.Télécharger = 'fugu-greeting.png';
à.href = URL.createObjectURL(goutte);
à.addEventListener('click', (et) => {
setTimeout(() => URL.revokeObjectURL(à.href), 30 * 1000);
});
à.Cliquez sur();
};
Mais attendez une minute. Mentalement, vous n'avez pas «téléchargé» de carte de vœux, vous avez
«Sauvé».
Plutôt que de vous montrer une boîte de dialogue «enregistrer» qui vous permet de choisir où placer le fichier,
le navigateur a téléchargé directement la carte de vœux sans intervention de l'utilisateur
et l'a mis directement dans votre dossier Téléchargements. Ce n'est pas génial.
Et s'il y avait un meilleur moyen?
Et si vous pouviez simplement ouvrir un fichier local, le modifier, puis enregistrer les modifications,
soit vers un nouveau fichier, soit retour au fichier d'origine que vous aviez initialement ouvert?
Il s'avère qu'il y en a. L'API du système de fichiers natif
vous permet d'ouvrir et de créer des fichiers et
répertoires, ainsi que les modifier et les enregistrer.
Alors, comment puis-je détecter les fonctionnalités d'une API?
L'API Native File System expose une nouvelle méthode window.chooseFileSystemEntries ()
.
Par conséquent, je dois charger conditionnellement différents modules d'importation et d'exportation selon que cette méthode est disponible. J'ai montré comment procéder ci-dessous.
const loadImportAndExport = () => {
si ('chooseFileSystemEntries' dans la fenêtre) {
Promise.là([
importer('./import_image.mjs'),
importer('./export_image.mjs'),
]);
} else {
Promise.là([
importer('./import_image_legacy.mjs'),
importer('./export_image_legacy.mjs'),
]);
}
};
Mais avant de plonger dans les détails de l'API Native File System,
permettez-moi de souligner rapidement le modèle d'amélioration progressive ici.
Sur les navigateurs qui ne prennent actuellement pas en charge l'API Native File System, je charge les scripts hérités.
Vous pouvez voir les onglets réseau de Firefox et Safari ci-dessous.
Cependant, sur Chrome, un navigateur prenant en charge l'API, seuls les nouveaux scripts sont chargés.
Ceci est rendu possible avec élégance grâce à
dynamique importer ()
, que tous les navigateurs modernes
Support.
Comme je l'ai dit plus tôt, l'herbe est assez verte ces jours-ci.
L'API du système de fichiers natif
Alors maintenant que j'ai abordé ce problème, il est temps d'examiner l'implémentation réelle basée sur l'API Native File System.
Pour importer une image, j'appelle window.chooseFileSystemEntries ()
et passez-le un accepte
propriété où je dis que je veux des fichiers image.
Les extensions de fichier ainsi que les types MIME sont pris en charge.
Cela se traduit par un descripteur de fichier, à partir duquel je peux obtenir le fichier réel en appelant getFile ()
.
const importImage = asynchrone () => {
try {
const handle = attendre la fenêtre.chooseFileSystemEntries({
accepte: [
{
la description: 'Image files',
mimeTypes: ['image/*'],
extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
revenir handle.getFile();
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
L'exportation d'une image est presque la même, mais cette fois
J'ai besoin de passer un paramètre de type de 'save-file'
au chooseFileSystemEntries ()
méthode.
De cela, j'obtiens une boîte de dialogue d'enregistrement de fichier.
Avec le fichier ouvert, ce n'était pas nécessaire car 'fichier ouvert'
est la valeur par défaut.
J'ai mis le accepte
paramètre similaire à avant, mais cette fois limité aux images PNG.
Encore une fois, je récupère un descripteur de fichier, mais plutôt que de récupérer le fichier,
cette fois, je crée un flux accessible en écriture en appelant createWritable ()
.
Ensuite, j'écris le blob, qui est l'image de ma carte de vœux, dans le fichier.
Enfin, je ferme le flux inscriptible.
Tout peut toujours échouer: le disque est peut-être à court d'espace,
il peut y avoir une erreur d'écriture ou de lecture, ou peut-être simplement que l'utilisateur annule la boîte de dialogue de fichier.
C'est pourquoi j'enroule toujours les appels dans un essayez ... attrapez
déclaration.
const exportImage = asynchrone (goutte) => {
try {
const handle = attendre la fenêtre.chooseFileSystemEntries({
taper: 'save-file',
accepte: [
{
la description: 'Image file',
extensions: ['png'],
mimeTypes: ['image/png'],
},
],
});
const inscriptible = attendre handle.createWritable();
attendre inscriptible.write(goutte);
attendre inscriptible.close();
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
Utilisation de l'amélioration progressive avec l'API Native File System,
Je peux ouvrir un fichier comme avant.
Le fichier importé est dessiné directement sur le canevas.
Je peux faire mes modifications et enfin les enregistrer avec une vraie boîte de dialogue de sauvegarde
où je peux choisir le nom et l'emplacement de stockage du fichier.
Le fichier est maintenant prêt à être conservé pour l'éternité.
Les API cibles de partage Web et de partage Web
Mis à part le stockage pour l'éternité, je veux peut-être partager ma carte de voeux.
C'est quelque chose que l'API Web Share et
L'API cible de partage Web me permet de le faire.
Les systèmes d'exploitation mobiles et, plus récemment, de bureau ont gagné le partage natif
mécanismes.
Par exemple, ci-dessous se trouve la feuille de partage de Safari de bureau sur macOS déclenchée à partir d'un article sur
ma Blog.
Lorsque vous cliquez sur le Partager l'article bouton, vous pouvez partager un lien vers l'article avec un ami, pour
exemple, via l'application native macOS Messages.
Le code pour y parvenir est assez simple. J'appelle navigator.share ()
et
passer un optionnel Titre
, texte
, et URL
dans un objet.
Mais que faire si je veux joindre une image? Le niveau 1 de l'API Web Share ne le prend pas encore en charge.
La bonne nouvelle est que Web Share Level 2 a ajouté des fonctionnalités de partage de fichiers.
try {
attendre navigateur.Compartir({
Titre: 'Check out this article:',
texte: `"${document.Titre}" by @tomayac:`,
URL: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.patate douce, err.un message);
}
Laissez-moi vous montrer comment faire fonctionner cela avec l'application de carte de voeux Fugu.
Tout d'abord, je dois préparer un Les données
objet avec un des dossiers
tableau constitué d'un objet blob, puis
à Titre
et un texte
. Ensuite, comme meilleure pratique, j'utilise le nouveau navigator.canShare ()
méthode qui fait
ce que son nom suggère:
Il me dit si le Les données
l'objet que j'essaie de partager peut techniquement être partagé par le navigateur.
Si navigator.canShare ()
me dit que les données peuvent être partagées, je suis prêt à
appel navigator.share ()
comme avant.
Parce que tout peut échouer, j'utilise à nouveau un essayez ... attrapez
bloquer.
const Compartir = asynchrone (Titre, texte, goutte) => {
const Les données = {
des dossiers: [
new Déposer([goutte], 'fugu-greeting.png', {
taper: goutte.taper,
}),
],
Titre: Titre,
texte: texte,
};
try {
si (!(navigateur.canShare(Les données))) {
throw new Erreur("Can't share data.", Les données);
}
attendre navigateur.Compartir(Les données);
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
Comme avant, j'utilise l'amélioration progressive.
Si les deux «Compartir»
et 'peut partager'
existent sur le navigateur
objet, alors seulement j'avance et
charge share.mjs
via dynamique importer ()
.
Sur les navigateurs comme Safari mobile qui ne remplissent qu'une des deux conditions, je ne charge pas
la fonctionnalité.
const loadShare = () => {
si («Compartir» dans navigateur && 'peut partager' dans navigateur) {
importer('./share.mjs');
}
};
Dans Fugu Greetings, si je touche le Compartir bouton sur un navigateur compatible comme Chrome sur Android,
la feuille de partage native s'ouvre.
Je peux, par exemple, choisir Gmail, et le widget de composition d'e-mails apparaît avec le
image jointe.
Ensuite, je veux parler des contacts, c'est-à-dire du carnet d'adresses d'un appareil
ou l'application de gestion de contacts.
Lorsque vous écrivez une carte de vœux, il n'est pas toujours facile d'écrire correctement
le nom de quelqu'un.
Par exemple, j'ai un ami Sergey qui préfère que son nom soit épelé en lettres cyrilliques. je suis
en utilisant un clavier allemand QWERTZ et je ne sais pas comment taper leur nom.
C'est un problème que l'API Contact Picker peut résoudre.
Puisque mon ami est stocké dans l'application Contacts de mon téléphone,
via l'API Contacts Picker, je peux accéder à mes contacts sur le Web.
Tout d'abord, je dois spécifier la liste des propriétés auxquelles je souhaite accéder.
Dans ce cas, je ne veux que les noms,
mais pour d'autres cas d'utilisation, je pourrais être intéressé par les numéros de téléphone, les e-mails, l'avatar
icônes ou adresses physiques.
Ensuite, je configure un options
objet et ensemble plusieurs
à vrai
, afin que je puisse sélectionner plus
plus d'une entrée.
Enfin, je peux appeler navigator.contacts.select ()
, qui renvoie les propriétés souhaitées
pour les contacts sélectionnés par l'utilisateur.
const getContacts = asynchrone () => {
const properties = ['name'];
const options = { plusieurs: vrai };
try {
revenir attendre navigateur.contacts.sélectionner(properties, options);
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
Et maintenant, vous avez probablement appris le modèle:
Je ne charge le fichier que lorsque l'API est réellement prise en charge.
si ('contacts' dans navigateur) {
importer('./contacts.mjs');
}
Dans Fugu Greeting, lorsque je touche le Contacts bouton et sélectionnez mes deux meilleurs copains,
Сергей Михайлович Брин et 劳伦斯 · 爱德华 · »拉里» · 佩奇,
vous pouvez voir comment le
le sélecteur de contacts est limité à afficher uniquement leurs noms,
mais pas leurs adresses e-mail ou d'autres informations telles que leurs numéros de téléphone.
Leurs noms sont ensuite dessinés sur ma carte de voeux.
L'API du Presse-papiers asynchrone
La prochaine étape consiste à copier et coller.
L'une de nos opérations préférées en tant que développeurs de logiciels est le copier-coller.
En tant qu'auteur de cartes de vœux, j'ai parfois envie de faire de même.
Je peux soit coller une image dans une carte de vœux sur laquelle je travaille,
ou copiez ma carte de vœux pour que je puisse continuer à la modifier à partir de
ailleurs.
L'API du Presse-papiers Async,
prend en charge le texte et les images.
Laissez-moi vous expliquer comment j'ai ajouté la prise en charge du copier-coller au Fugu
Salutations app.
Pour copier quelque chose dans le presse-papiers du système, je dois y écrire.
le navigator.clipboard.write ()
prend un tableau d'éléments de presse-papiers comme un
paramètre.
Chaque élément du presse-papiers est essentiellement un objet avec un blob comme valeur et le type de blob
comme clé.
const copie = asynchrone (goutte) => {
try {
attendre navigateur.presse-papiers.write([
new Presse-papiers({
[goutte.taper]: goutte,
}),
]);
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
Pour coller, je dois faire une boucle sur les éléments du presse-papiers que j'obtiens en appelant
navigator.clipboard.read ()
.
La raison en est que plusieurs éléments du presse-papiers peuvent se trouver dans le presse-papiers dans
différentes représentations.
Chaque élément du presse-papiers a un les types
champ qui m'indique les types MIME des
Ressources.
J'appelle l'élément du presse-papiers getType ()
méthode, en passant la
Type MIME que j'ai obtenu auparavant.
const pâte = asynchrone () => {
try {
const clipboardItems = attendre navigateur.presse-papiers.read();
pour (const clipboardItem of clipboardItems) {
try {
pour (const taper of clipboardItem.les types) {
const goutte = attendre clipboardItem.getType(taper);
revenir goutte;
}
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
}
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
Et c'est presque inutile de le dire maintenant. Je ne fais cela que sur les navigateurs compatibles.
si ('clipboard' dans navigateur && 'write' dans navigateur.presse-papiers) {
importer('./clipboard.mjs');
}
Alors, comment cela fonctionne-t-il dans la pratique? J'ai une image ouverte dans l'application macOS Preview et
copiez-le dans le presse-papiers.
Quand je clique Pâte, l'application Fugu Greetings me demande alors
si je veux autoriser l'application à voir le texte et les images dans le presse-papiers.
Enfin, après avoir accepté l'autorisation, l'image est ensuite collée dans l'application.
L'inverse fonctionne aussi.
Permettez-moi de copier une carte de vœux dans le presse-papiers.
Lorsque j'ouvre ensuite Aperçu et clique sur Déposer et alors Nouveau à partir du presse-papiers,
la carte de voeux est collée dans une nouvelle image sans titre.
L'API Badging
Une autre API utile est l'API Badging.
En tant que PWA installable, Fugu Greetings a bien sûr une icône d'application
que les utilisateurs peuvent placer sur la station d'accueil de l'application ou sur l'écran d'accueil.
Un moyen amusant et simple de démontrer l'API est de (ab) l'utiliser dans Fugu Greetings
comme compteur de coups de stylo.
J'ai ajouté un écouteur d'événement qui incrémente le compteur de traits de stylet chaque fois que le pointeur vers le bas
l'événement se produit
puis définit le badge d'icône mis à jour.
Chaque fois que la toile est effacée, le compteur se réinitialise et le badge est supprimé.
laisser strokes = 0;canvas.addEventListener('pointerdown', () => {
navigateur.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigateur.setAppBadge(strokes);
});
Cette fonctionnalité est une amélioration progressive, donc la logique de chargement est comme d'habitude.
si ('setAppBadge' dans navigateur) {
importer('./badge.mjs');
}
Dans cet exemple, j'ai dessiné les nombres de un à sept, en utilisant un trait de stylo
par numéro.
Le compteur de badges sur l'icône est maintenant à sept.
L'API de synchronisation en arrière-plan périodique
Vous voulez commencer chaque journée avec quelque chose de nouveau?
Une caractéristique intéressante de l'application Fugu Greetings est qu'elle peut vous inspirer chaque matin
avec une nouvelle image de fond pour commencer votre carte de voeux.
L'application utilise l'API Periodic Background Sync
pour y parvenir.
La première étape consiste à S'inscrire un événement de synchronisation périodique dans l'enregistrement du technicien de service.
Il écoute une balise de synchronisation appelée 'image-du-jour'
et a un intervalle minimum d'un jour,
afin que l'utilisateur puisse obtenir une nouvelle image d'arrière-plan toutes les 24 heures.
const registerPeriodicBackgroundSync = asynchrone () => {
const enregistrement = attendre navigateur.serviceWorker.prêt;
try {
enregistrement.periodicSync.S'inscrire('image-of-the-day-sync', {
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.Erreur(err.patate douce, err.un message);
}
};
La deuxième étape consiste à Ecoutez pour le periodicsync
événement dans le service worker.
Si la balise d'événement est 'image-du-jour'
, c'est-à-dire celui qui a été enregistré auparavant,
l'image du jour est récupérée via le getImageOfTheDay ()
une fonction,
et le résultat s'est propagé à tous les clients, afin qu'ils puissent mettre à jour leurs toiles et
caches.
soi.addEventListener('periodicsync', (syncEvent) => {
si (syncEvent.étiqueter === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(asynchrone () => {
const goutte = attendre getImageOfTheDay();
const clients = attendre soi.clients.matchAll();
clients.forEach((client) => {
client.postMessage({
image: goutte,
});
});
})()
);
}
});
Encore une fois, il s'agit vraiment d'une amélioration progressive, de sorte que le code n'est chargé que lorsque le
L'API est prise en charge par le navigateur.
Cela s'applique à la fois au code client et au code du technicien de service.
Sur les navigateurs non compatibles, aucun d'eux n'est chargé.
Notez comment dans le service worker, au lieu d'une dynamique importer ()
(qui n'est pas pris en charge dans un contexte de service worker
encore),
J'utilise le classique
importScripts ()
.
const enregistrement = attendre navigateur.serviceWorker.prêt;
si (enregistrement && 'periodicSync' dans enregistrement) {
importer('./periodic_background_sync.mjs');
}
si ('periodicSync' dans soi.enregistrement) {
importScripts('./image_of_the_day.mjs');
}
Dans Fugu Greetings, appuyez sur la touche Fond d'écran le bouton révèle l'image de la carte de voeux du jour
qui est mis à jour chaque jour via l'API Periodic Background Sync.
API de déclencheurs de notification
Parfois, même avec beaucoup d'inspiration, vous avez besoin d'un coup de pouce pour terminer une salutation commencée
carte.
Il s'agit d'une fonctionnalité activée par l'API Notification Triggers.
En tant qu'utilisateur, je peux saisir une heure à laquelle je souhaite être poussé à terminer ma carte de vœux.
Quand ce moment viendra, je recevrai une notification indiquant que ma carte de voeux est en attente.
Après avoir demandé l'heure cible,
l'application planifie la notification avec un showTrigger
.
Cela peut être un TimestampTrigger
avec la date cible précédemment sélectionnée.
La notification de rappel sera déclenchée localement, aucun côté réseau ou serveur n'est nécessaire.
const targetDate = promptTargetDate();
si (targetDate) {
const enregistrement = attendre navigateur.serviceWorker.prêt;
enregistrement.showNotification('Reminder', {
étiqueter: 'reminder',
corps: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
Comme pour tout ce que j'ai montré jusqu'à présent, il s'agit d'une amélioration progressive,
donc le code n'est chargé que conditionnellement.
si ('Notification' dans la fenêtre && 'showTrigger' dans Notification.prototype) {
importer('./notification_triggers.mjs');
}
Quand je vérifie le Rappel case à cocher dans Fugu Greetings, une invite demande
moi quand je veux qu'on me rappelle de terminer ma carte de vœux.
Lorsqu'une notification planifiée se déclenche dans Fugu Greetings,
il est affiché comme n'importe quelle autre notification, mais comme je l'ai déjà écrit,
il ne nécessitait pas de connexion réseau.
L'API Wake Lock
Je souhaite également inclure l'API Wake Lock.
Parfois, vous avez juste besoin de rester assez longtemps à l'écran jusqu'à l'inspiration
vous embrasse.
Le pire qui puisse arriver est que l'écran s'éteigne.
L'API Wake Lock peut empêcher que cela se produise.
La première étape consiste à obtenir un verrou de réveil avec le navigator.wakelock.request, méthode ()
.
Je lui passe la ficelle 'écran'
pour obtenir un verrouillage de réveil de l'écran.
J'ajoute ensuite un écouteur d'événement pour être informé lorsque le verrou de réveil est libéré.
Cela peut se produire, par exemple, lorsque la visibilité de l'onglet change.
Si cela se produit, je peux, lorsque l'onglet redevient visible, obtenir à nouveau le verrou de réveil.
laisser wakeLock = nul;
const requestWakeLock = asynchrone () => {
wakeLock = attendre navigateur.wakeLock.request('écran');
wakeLock.addEventListener('release', () => {
console.Journal('Wake Lock was released');
});
console.Journal('Wake Lock is active');
};const handleVisibilityChange = () => {
si (wakeLock !== nul && document.visibilityState === 'visible') {
requestWakeLock();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener('fullscreenchange', handleVisibilityChange);
Oui, il s'agit d'une amélioration progressive, je n'ai donc besoin de la charger que lorsque le navigateur
prend en charge l'API.
si ('wakeLock' dans navigateur && 'request' dans navigateur.wakeLock) {
importer('./wake_lock.mjs');
}
Dans Fugu Greetings, il y a un insomnie case à cocher qui, lorsqu'elle est cochée, garde le
écran éveillé.
L'API de détection d'inactivité
Parfois, même si vous regardez l'écran pendant des heures,
c'est tout simplement inutile et vous ne pouvez pas vous faire la moindre idée de ce qu'il faut faire avec votre carte de voeux.
L'API de détection d'inactivité permet à l'application de détecter le temps d'inactivité de l'utilisateur.
Si l'utilisateur est inactif trop longtemps, l'application se réinitialise à l'état initial
et efface la toile.
Cette API est actuellement fermée derrière le
autorisation de notifications,
étant donné que de nombreux cas d'utilisation de la détection d'inactivité en production sont liés aux notifications,
par exemple, pour envoyer une notification uniquement à un appareil que l'utilisateur utilise actuellement activement.
Après m'être assuré que l'autorisation de notification est accordée, j'instancie le
détecteur de ralenti.
J'enregistre un écouteur d'événements qui écoute les modifications inactives, qui inclut l'utilisateur et
l'état de l'écran.
L'utilisateur peut être actif ou inactif,
et l'écran peut être déverrouillé ou verrouillé.
Si l'utilisateur est inactif, le canevas s'efface.
Je donne au détecteur de ralenti un seuil de 60 secondes.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.Journal(`Idle change: ${userState}, ${screenState}.`);
si (userState === 'idle') {
clearCanvas();
}
});attendre idleDetector.démarrer({
au seuil: 60000,
signal,
});
Et comme toujours, je ne charge ce code que lorsque le navigateur le prend en charge.
si ('IdleDetector' dans la fenêtre) {
importer('./idle_detection.mjs');
}
Dans l'application Fugu Greetings, le canevas s'efface lorsque le Éphémère la case à cocher est
cochée et l'utilisateur est inactif pendant trop longtemps.
Fermeture
Ouf, quelle balade. Tant d'API dans un seul exemple d'application.
Et, rappelez-vous, je ne fais jamais payer à l'utilisateur le coût du téléchargement
pour une fonctionnalité que leur navigateur ne prend pas en charge.
En utilisant l'amélioration progressive, je m'assure que seul le code pertinent est chargé.
Et comme avec HTTP / 2, les requêtes sont bon marché, ce modèle devrait bien fonctionner pour beaucoup de
applications,
bien que vous souhaitiez peut-être envisager un bundler pour les applications très volumineuses.
L'application peut sembler un peu différente sur chaque navigateur car toutes les plates-formes ne prennent pas en charge toutes les fonctionnalités,
mais la fonctionnalité de base est toujours là - progressivement améliorée en fonction des capacités du navigateur particulier.
Notez que ces fonctionnalités peuvent changer même dans un seul et même navigateur,
selon que l'application s'exécute en tant qu'application installée ou dans un onglet de navigateur.
Si vous êtes intéressé par le Salutations Fugu application,
va chercher et fourchez-le sur GitHub.
L'équipe Chromium travaille d'arrache-pied pour rendre l'herbe plus verte en ce qui concerne les API Fugu avancées.
En appliquant une amélioration progressive dans le développement de mon application,
Je m'assure que tout le monde a une bonne et solide expérience de base,
mais que les personnes utilisant des navigateurs prenant en charge davantage d'API de plate-forme Web obtiennent une expérience encore meilleure.
J'ai hâte de voir ce que vous faites avec l'amélioration progressive de vos applications.
Remerciements
Je suis reconnaissant de Christian Liebel et
Hemanth HM qui ont tous deux contribué à Fugu Greetings.
Cet article a été révisé par Joe medley et
Kayce Basques.
Jake Archibald m'a aidé à découvrir la situation
avec dynamique importer ()
dans un contexte de service worker.