Modern tarayıcılar için geliştirme yapıp 2003'teymiş gibi aşamalı olarak geliştirme
Mart 2003'te Nick Finck ve Steve Champeon progresif geliştirme kavramı ile web tasarımı dünyasını şaşırttı. Bu kavram, web tasarımı için önce temel web sayfası içeriğinin yüklenmesini vurgulayan, ardından ardından içeriğe giderek daha fazla incelikli ve teknik olarak titizlikli sunum katmanları ekleyen bir web tasarımı stratejisiydi. 2003'te aşamalı geliştirme, o zamanlar modern CSS özelliklerini, göze çarpmayan JavaScript'i ve hatta ölçeklenebilir vektör grafiklerini kullanmakla ilgiliydi. 2020 ve sonrasındaki aşamalarda, modern tarayıcı özelliklerini kullanarak aşamalı iyileştirmeler yapılacak.
Modern JavaScript
JavaScript'ten bahsetmişken, ES 2015'in en son temel JavaScript özelliklerine ilişkin tarayıcı desteğinin durumu çok iyi.
Yeni standart; umutlar, modüller, sınıflar, şablon literalleri, ok işlevleri, let
ve const
, varsayılan parametreler, jeneratörler, yapı bozma atama, geri kalan ve dağıtma, Map
/Set
, WeakMap
/WeakSet
ve daha fazlasını içerir.
Tüm tarayıcılar desteklenir.
ES 2017 özelliği olan ve en sevdiğim işlevlerden biri olan arayüz dışı işlevler, tüm popüler tarayıcılarda kullanılabilir.
async
ve await
anahtar kelimeleri, söz zincirlerinin açıkça yapılandırılması gerekmeden, söze dayalı ve eşzamansız davranışın daha net bir şekilde yazılmasını sağlar.
İsteğe bağlı zincirleme ve boş birleştirme gibi ES 2020'de eklenen yeni dil özellikleri bile çok hızlı bir şekilde destek kapsamına alındı. Aşağıda kod örneğini görebilirsiniz. Temel JavaScript özellikleri söz konusu olduğunda, durum bugün olduğundan çok daha iyi.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
// Expected output: undefined
console.log(0 ?? 42);
// Expected output: 0
Örnek uygulama: Fugu Greetings
Bu makalede, Fugu Greetings (GitHub) adlı basit bir PWA kullanıyorum. Bu uygulamanın adı, web'e Android/iOS/masaüstü uygulamalarının tüm özelliklerini kazandırma çabası olan Project Fugu'ya 🐡 bir göndermedir. Proje hakkında daha fazla bilgiyi açılış sayfasında bulabilirsiniz.
Fugu Greetings, sanal tebrik kartları oluşturup sevdiklerinize göndermenize olanak tanıyan bir çizim uygulamasıdır. Bu örnek, PWA'nın temel kavramlarını göstermektedir. Güvenilir ve tamamen çevrimdışı olarak kullanılabildiği için ağ bağlantınız olmasa bile bu çözümü kullanabilirsiniz. Ayrıca cihazın ana ekranına yüklenebilir ve bağımsız bir uygulama olarak işletim sistemiyle sorunsuz bir şekilde entegre olur.
Progresif geliştirme
Bu bilgilerden sonra kademeli iyileştirme hakkında konuşmanın zamanı geldi. MDN Web Dokümanlar Sözlüğü, kavramı şu şekilde tanımlar:
Kademeli iyileştirme, mümkün olduğunca çok sayıda kullanıcıya temel içerik ve işlevsellik sunarken yalnızca gerekli tüm kodu çalıştırabilen en modern tarayıcıların kullanıcılarına mümkün olan en iyi deneyimi sunan bir tasarım felsefesidir.
Özellik algılama genellikle tarayıcıların daha modern işlevleri işleyip işleyemeyeceğini belirlemek için kullanılır. Çoklu doldurma ise genellikle JavaScript ile eksik özellikleri eklemek için kullanılır.
[…]
Progresif geliştirme, web geliştiricilerin mümkün olan en iyi web sitelerini geliştirirken bu web sitelerini birden fazla bilinmeyen kullanıcı aracısında çalıştırmasına olanak tanıyan faydalı bir tekniktir. Sorunsuz düşüş, kademeli iyileştirmeyle ilgili ancak aynı değildir ve genellikle kademeli iyileştirmenin tam tersi yönde bir hareket olarak görülür. Gerçekte her iki yaklaşım da geçerlidir ve genellikle birbirini tamamlayabilir.
MDN katkıda bulunanlar
Her tebrik kartını sıfırdan başlatmak gerçekten külfetli olabilir.
Öyleyse neden kullanıcıların resimleri içe aktarıp oradan başlamalarını sağlayan bir özelliğe sahip değil misiniz?
Geleneksel bir yaklaşımla bunun için <input type=file>
öğesi kullanırsınız.
Öncelikle öğeyi oluşturur, type
değerini 'file'
olarak ayarlar ve accept
mülküne MIME türleri eklersiniz. Ardından öğeyi programatik olarak "tıklar" ve değişiklikleri beklersiniz.
Seçtiğiniz resimler doğrudan kanvas üzerine aktarılır.
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();
});
};
Bir içe aktarma özelliği olduğunda, kullanıcıların tebrik kartlarını yerel olarak kaydedebilmeleri için muhtemelen bir dışa aktarma özelliği bulunmalıdır.
Dosyaları kaydetmenin geleneksel yolu, download
özelliğine sahip bir ana sayfa bağlantısı ve href
olarak bir blob URL'si oluşturmaktır.
Ayrıca, indirme işlemini tetiklemek için bu düğmeyi programatik olarak "tıklamanız" gerekir. Ayrıca, bellek sızıntısını önlemek için blob nesnesi URL'sini iptal etmeyi unutmayın.
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();
};
Lütfen bir dakika bekleyin. Zihinsel olarak bir tebrik kartı "indirmemiş", "kaydetmişsiniz" demektir. Tarayıcı, dosyayı nereye koyacağınızı seçmenize olanak tanıyan bir "kaydet" iletişim kutusu göstermek yerine, kullanıcı etkileşimi olmadan doğrudan tebrik kartını indirip İndirilenler klasörünüze yerleştirdi. Bu hiç iyi değil.
Daha iyi bir yol olsaydı ne olurdu? Yerel bir dosyayı açıp düzenledikten sonra değişiklikleri yeni bir dosyaya veya ilk açtığınız orijinal dosyaya kaydedebilseydiniz ne olurdu? File System Access API, dosya ve dizinleri açıp oluşturmanın yanı sıra bunları değiştirmenize ve kaydetmenize olanak tanır.
Peki bir API'de nasıl özellik algılayabilirim?
File System Access API yeni bir window.chooseFileSystemEntries()
yöntemini sunuyor.
Bu nedenle, bu yöntemin kullanılabilir olup olmadığına bağlı olarak koşullu olarak farklı içe ve dışa aktarma modülleri yüklemem gerekiyor. Bunun nasıl yapılacağını aşağıda görebilirsiniz.
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'),
]);
}
};
Ancak File System Access API ayrıntılarına geçmeden önce, aşamalı iyileştirme modelini kısaca vurgulamak isterim. Şu anda File System Access API'yi desteklemeyen tarayıcılarda eski komut dosyalarını yüklüyorum. Firefox ve Safari'nin ağ sekmelerini aşağıda görebilirsiniz.
Ancak API'yi destekleyen bir tarayıcı olan Chrome'da yalnızca yeni komut dosyaları yüklenir.
Bu, tüm modern tarayıcıların desteklediği dinamik import()
sayesinde zarif bir şekilde mümkün kılınmaktadır.
Daha önce de söylediğim gibi, bu günlerde işler oldukça yolunda.
File System Access API
Bu konuyu ele aldıktan sonra, File System Access API'ye dayalı gerçek uygulamaya bakmanın zamanı geldi.
Resim içe aktarmak için window.chooseFileSystemEntries()
işlevini çağırıyorum ve resim dosyaları istediğimi belirten bir accepts
mülkü iletiyorum.
Hem MIME türleri hem de dosya uzantıları desteklenir.
Bu işlem sonucunda, getFile()
komutunu çağırarak gerçek dosyayı alabileceğim bir dosya işleyici oluşturulur.
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);
}
};
Resim dışa aktarma işlemi neredeyse aynıdır ancak bu sefer chooseFileSystemEntries()
yöntemine 'save-file'
türündeki bir parametre göndermem gerekiyor.
Bu işlemden sonra bir dosya kaydetme iletişim kutusu görüyorum.
Dosya açıkken 'open-file'
varsayılan olduğu için bu gerekli değildi.
accepts
parametresini öncekine benzer şekilde ayarladım ancak bu sefer yalnızca PNG resimleriyle sınırladım.
Yine bir dosya tutamaç döndürülür ancak bu sefer dosyayı almak yerine createWritable()
işlevini çağırarak yazılabilir bir akış oluştururum.
Ardından, tebrik kartı resmim olan blob'u dosyaya yazarım.
Son olarak, yazılabilir akışı kapatıyorum.
Her şey her zaman başarısız olabilir: Diskte yer kalmamış olabilir, yazma veya okuma hatası olabilir ya da kullanıcı dosya iletişim kutusunu iptal etmiş olabilir.
Bu nedenle, çağrıları her zaman bir try...catch
ifadesi içine alırım.
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);
}
};
File System Access API ile aşamalı geliştirmeyi kullanarak dosyaları eskisi gibi açabilirim. İçe aktarılan dosya doğrudan tuvale çizilir. Düzenlemeler yapıp dosyanın adını ve depolama konumunu seçebileceğim gerçek bir kaydetme iletişim kutusuyla dosyaları kaydedebilirim. Dosya artık sonsuza kadar saklanacak şekilde hazırdır.
Web Share ve Web Share Target API'leri
Sonsuza kadar depolamanın dışında belki de tebrik kartımı paylaşmak isterim. Web Share API ve Web Share Target API bunu yapmama olanak tanıyor. Mobil ve yakın zamanda masaüstü işletim sistemleri, yerleşik paylaşım mekanizmalarına sahip. Örneğin, aşağıdaki resimde macOS'te masaüstü Safari'nin, blogumdaki bir makaleden tetiklenen paylaşım sayfası gösterilmektedir. Makaleyi Paylaş düğmesini tıkladığınızda makalenin bağlantısını bir arkadaşınızla (ör. macOS Mesajlar uygulaması üzerinden) paylaşabilirsiniz.
Bunu gerçekleştirmek için kullanacağınız kod oldukça basittir. navigator.share()
işlevini çağırıyorum ve bir nesnede isteğe bağlı title
, text
ve url
parametrelerini ilerliyorum.
Peki bir resim eklemek istersem ne olur? Web Share API'nin 1. düzeyi henüz bunu desteklemiyor.
Neyse ki Web Paylaşımı Düzeyi 2'ye dosya paylaşım özellikleri eklenmiştir.
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);
}
Bunu Fugu tebrik kartı uygulamasıyla nasıl yapacağınızı göstereyim.
Öncelikle, bir blobdan oluşan bir files
dizisi içeren bir data
nesnesi, ardından bir title
ve bir text
hazırlamam gerekiyor. Ardından, en iyi uygulama olarak, adının belirttiği şekilde yeni navigator.canShare()
yöntemini kullanıyorum:
Paylaşmaya çalıştığım data
nesnesinin tarayıcı tarafından teknik olarak paylaşılıp paylaşılamayacağını söylüyor.
navigator.canShare()
, verilerin paylaşılabileceğini söylerse daha önce olduğu gibi navigator.share()
numarasını aramaya hazırım.
Her şey başarısız olabileceği için yine bir try...catch
bloku kullanıyorum.
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);
}
};
Daha önce olduğu gibi progresif geliştirmeyi kullanıyorum.
navigator
nesnesinde hem 'share'
hem de 'canShare'
varsa yalnızca bu durumda ileri gidip dinamik import()
aracılığıyla share.mjs
öğesini yüklerim.
Mobil Safari gibi yalnızca iki koşuldan birini karşılayan tarayıcılarda işlev yüklemiyorum.
const loadShare = () => {
if ('share' in navigator && 'canShare' in navigator) {
import('./share.mjs');
}
};
Fugu Greetings'da, Android'de Chrome gibi desteklenen bir tarayıcıda Paylaş düğmesine dokunursam yerleşik paylaşım sayfası açılır. Örneğin, Gmail'i seçtiğimde, e-posta oluşturucu widget'ı, resmi ekleyerek açılır.
Contact Picker API
Ardından, cihazın adres defteri veya kişi yöneticisi uygulaması olan kişilerden bahsetmek istiyorum. Bir tebrik kartı yazarken kişinin adını doğru yazmak her zaman kolay olmayabilir. Örneğin, Sergey adının Kiril harfleriyle yazılmasını tercih eden bir arkadaşım var. Almanca QWERTZ klavye kullanıyorum ve adlarını nasıl yazacağımı bilmiyorum. Bu, Contact Picker API'nin çözebileceği bir sorundur. Arkadaşım telefonumun kişiler uygulamasında kayıtlı olduğundan Kişiler Seçici API'sını kullanarak web'den kişilerime ulaşabiliyorum.
Öncelikle, erişmek istediğim mülklerin listesini belirtmem gerekiyor.
Bu durumda yalnızca adları istiyorum ancak diğer kullanım alanları için telefon numaraları, e-postalar, avatar simgeleriyle fiziksel adresler de ilgimi çekebilir.
Daha sonra, birden fazla giriş seçmek için bir options
nesnesi yapılandırıp multiple
değerini true
olarak ayarlıyorum.
Son olarak, kullanıcı tarafından seçilen kişiler için istenen özellikleri döndüren navigator.contacts.select()
işlevini çağırabilirim.
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);
}
};
Şimdiye kadar muhtemelen şu kalıbı öğrendiniz: Yalnızca API gerçekten desteklendiğinde dosyayı yüklerim.
if ('contacts' in navigator) {
import('./contacts.mjs');
}
Fugu Greeting'de Kişiler düğmesine dokunup en iyi iki arkadaşım Сергей Михайлович Брин ve 劳伦斯·爱德华·"拉里"·佩奇'yi seçtiğimde, kişiler seçicinin yalnızca adlarını göstermekle sınırlı olduğunu, e-posta adreslerini veya telefon numaraları gibi diğer bilgileri göstermediğini görebilirsiniz. Ardından, isimlerini tebrik kartıma çiziyorum.
Eşzamansız Clipboard API
Bir sonraki konu kopyalama ve yapıştırma. Yazılım geliştiricileri olarak en sevdiğimiz işlemlerden biri kopyalama ve yapıştırmadır. Kart yazarı olarak bazen aynısını yapmak isterim. Üzerinde çalıştığım bir tebrik kartına resim yapıştırmak veya tebrik kartımı başka bir yerden düzenlemeye devam edebilmek için kopyalamak istiyorum. Async Clipboard API hem metni hem de görselleri destekler. Fugu Greetings uygulamasına kopyalama ve yapıştırma desteğini nasıl eklediğimi adım adım anlatacağım.
Bir şeyi sistemin panosuna kopyalamak için panoya yazmam gerekiyor.
navigator.clipboard.write()
yöntemi, parametre olarak bir pano öğesi dizisi alır.
Her panoya kopyalanan öğe, temelde değeri bir blob, anahtarı ise blob türü olan bir nesnedir.
const copy = async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
console.error(err.name, err.message);
}
};
Yapıştırmak için navigator.clipboard.read()
çağrısını kullanarak elde ettiğim pano öğelerini döngüden geçirmem gerekiyor.
Bunun nedeni, panoda farklı şekillerde birden fazla pano öğesinin bulunabilmesidir.
Her pano öğesinde, mevcut kaynakların MIME türlerini belirten bir types
alanı var.
Daha önce aldığım MIME türünü ileterek, panosundaki öğenin getType()
yöntemini çağırıyorum.
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);
}
};
Bu konuda söylenecek çok şey var. Bu işlemi yalnızca desteklenen tarayıcılarda yaparım.
if ('clipboard' in navigator && 'write' in navigator.clipboard) {
import('./clipboard.mjs');
}
Peki bu nasıl çalışır? macOS Önizleme uygulamasında açık bir resmim var ve bu resmi panoya kopyalıyorum. Yapıştır'ı tıkladığımda Fugu Greetings uygulaması bana panodaki metin ve resimleri görmesine izin vermek isteyip istemediğimi soruyor.
Son olarak, izin kabul edildikten sonra resim uygulamaya yapıştırılır. Bunun tersi de geçerlidir. Bir tebrik kartını panoya kopyalayayım. Ardından Önizleme'yi açıp Dosya'yı ve ardından Kopya Kutusundan Yeni'yi tıkladığımda tebrik kartı, yeni bir adsız resme yapıştırılıyor.
Badging API
Badging API de faydalı API'lerden biridir.
Yüklenebilir bir PWA olarak Fugu Greetings'in, kullanıcıların uygulama paneline veya ana ekrana yerleştirebileceği bir uygulama simgesi vardır.
API'yi göstermenin eğlenceli ve kolay bir yolu, Fugu Greetings'da kalem vuruşları sayacı olarak kullanmaktır.
pointerdown
etkinliği gerçekleştiğinde kalem vuruşları sayacını artıran ve ardından güncellenmiş simge rozetini ayarlayan bir etkinlik işleyici ekledim.
Kanvas temizlendiğinde sayaç sıfırlanır ve rozet kaldırılır.
let strokes = 0;
canvas.addEventListener('pointerdown', () => {
navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigator.setAppBadge(strokes);
});
Bu özellik aşamalı bir geliştirme olduğundan yükleme mantığı normal şekildedir.
if ('setAppBadge' in navigator) {
import('./badge.mjs');
}
Bu örnekte, her sayı için bir kalem darbesi kullanarak bir ile yedi arasındaki sayıları çizdim. Simgedeki rozet sayacı artık yedi.
Periyodik Arka Plan Senkronizasyonu API'si
Her güne yeni bir şeyle başlamak ister misiniz? Fugu Greetings uygulamasının güzel özelliklerinden biri, her sabah yeni bir arka plan resmiyle sizi selam kartınıza başlamaya teşvik etmesidir. Uygulama bunu yapmak için Periodic Background Sync API'yi kullanır.
İlk adım, hizmet çalışanı kaydına düzenli senkronizasyon etkinliği kaydetmektir.
'image-of-the-day'
adlı bir senkronizasyon etiketini dinler ve en az bir günlük bir aralığa sahiptir. Böylece kullanıcı 24 saatte bir yeni bir arka plan resmi alabilir.
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);
}
};
İkinci adım, hizmet çalışanında periodicsync
etkinliğine kulak vermek olacaktır.
Etkinlik etiketi 'image-of-the-day'
ise (yani daha önce kaydedilen etiket) günün resmi getImageOfTheDay()
işlevi aracılığıyla alınır ve sonuç tüm istemcilere dağıtılır. Böylece istemciler tuvallerini ve önbelleğe alınmış verilerini güncelleyebilir.
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,
});
});
})()
);
}
});
Bu da yine aşamalı bir geliştirmedir. Bu nedenle kod yalnızca API tarayıcı tarafından desteklendiğinde yüklenir.
Bu kural hem istemci kodu hem de Service Worker kodu için geçerlidir.
Desteklenmeyen tarayıcılarda bu iki dosya da yüklenmez.
Service Worker'da (henüz bir hizmet çalışanı bağlamında desteklenmeyen) dinamik import()
yerine klasik importScripts()
kullandığımı unutmayın.
// 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');
}
Fugu Greetings'da Duvar kağıdı düğmesine bastığınızda, Düzenli Arka Plan Senkronizasyonu API'si aracılığıyla her gün güncellenen günün tebrik kartı resmi gösterilir.
Notification Triggers API
Bazen çok fazla ilham olsa bile, başladığınız bir tebrik kartını tamamlamak için yönlendirmeye ihtiyacınız olur. Bu özellik, Notification Triggers API tarafından etkinleştirilir. Kullanıcı olarak, tebrik kartımı tamamlamam için otomatik hatırlatma istediğim bir zaman girebilirim. Bu tarih geldiğinde, tebrik kartımın beklediğine dair bir bildirim alacağım.
Uygulama, hedef zaman istedikten sonra bildirimi showTrigger
ile programlar.
Bu, önceden seçilen hedef tarihi içeren bir TimestampTrigger
olabilir.
Hatırlatıcı bildirimi yerel olarak tetiklenir; ağ veya sunucu tarafı gerekmez.
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),
});
}
Şimdiye kadar gösterdiğim diğer her şeyde olduğu gibi bu da progresif bir geliştirme olduğu için kod yalnızca koşullu olarak yükleniyor.
if ('Notification' in window && 'showTrigger' in Notification.prototype) {
import('./notification_triggers.mjs');
}
Fugu Greetings'da Hatırlatıcı onay kutusunu işaretlediğimde, tebrik kartımı tamamlamam gerektiğini ne zaman hatırlatılmasını istediğimi soran bir istem gösteriliyor.
Fugu Greetings'da planlanmış bir bildirim tetiklendiğinde, diğer bildirimler gibi gösterilir ancak daha önce de belirttiğim gibi ağ bağlantısı gerektirmez.
Wake Lock API
Wake Lock API'yi de dahil etmek istiyorum. Bazen ilham size gelene kadar ekrana uzun süre bakmanız yeterlidir. Bu durumda en kötü ihtimal ekranın kapanmasıdır. Wake Lock API, bunun olmasını önleyebilir.
İlk adım, navigator.wakelock.request method()
ile bir uyanık kalma kilidi edinmektir.
Ekran uyanık kalma kilidi elde etmek için 'screen'
dizesini iletiyorum.
Ardından, uyanma kilidi açıldığında bilgilendirilmek için bir etkinlik dinleyici eklerim.
Örneğin, sekme görünürlüğü değiştiğinde bu durumla karşılaşabilirsiniz.
Bu durumda, sekme tekrar görünür hale geldiğinde uyanma kilidini yeniden edinebilirim.
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);
Evet, bu aşamalı bir geliştirmedir. Bu nedenle, yalnızca tarayıcı API'yi desteklediğinde yüklemem gerekir.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
import('./wake_lock.mjs');
}
Fugu Greetings'te, işaretlendiğinde ekranı açık tutan bir Uykusuzluk onay kutusu bulunur.
Idle Detection API
Bazen saatlerce ekrana baksanız bile hiçbir şey aklınıza gelmez ve tebrik kartınızla ne yapacağınızı bilemezsiniz. Idle Detection API, uygulamanın kullanıcının boşta kalma süresini algılamasına olanak tanır. Kullanıcı uzun süre boyunca işlem yapmazsa uygulama ilk duruma sıfırlanır ve tuval temizlenir. Boş ekran algılamanın birçok üretim kullanım alanı bildirimlerle ilgili olduğundan (ör. yalnızca kullanıcının o anda etkin olarak kullandığı bir cihaza bildirim göndermek için) bu API şu anda bildirim izni kapsamındadır.
Bildirim izninin verildiğinden emin olduktan sonra boşta kalma algılayıcısını örneklendiririm. Kullanıcıyı ve ekran durumunu içeren boşta kalma değişikliklerini dinleyen bir etkinlik dinleyicisi kaydediyorum. Kullanıcı etkin veya boşta olabilir, ekran kilidi açılabilir veya kilitlenebilir. Kullanıcı işlem yapmazsa tuval temizlenir. Boşta kalma algılayıcısına 60 saniyelik bir eşik değeri veriyorum.
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,
});
Her zaman olduğu gibi, bu kodu yalnızca tarayıcı desteklediğinde yüklerim.
if ('IdleDetector' in window) {
import('./idle_detection.mjs');
}
Fugu Greetings uygulamasında, Geçici onay kutusu işaretlendiğinde ve kullanıcı çok uzun süre hareketsiz kaldığında tuval temizlenir.
Kapanış
Vay canına. Tek bir örnek uygulamada bu kadar çok API var. Ayrıca, kullanıcının tarayıcısının desteklemediği bir özelliğin indirme maliyetini hiçbir zaman kullanıcıdan ödemesini istemem. Progresif geliştirmeyi kullanarak yalnızca alakalı kodun yüklenmesini sağlıyorum. HTTP/2'de istekler ucuz olduğundan bu kalıp birçok uygulama için işe yarayabilir. Ancak gerçekten büyük uygulamalar için bir paketleyici kullanmayı düşünebilirsiniz.
Tüm platformlar tüm özellikleri desteklemediğinden uygulama her tarayıcıda biraz farklı görünebilir. Ancak temel işlevler her zaman mevcuttur ve ilgili tarayıcının özelliklerine göre aşamalı olarak geliştirilir. Bu özelliklerin, uygulamanın yüklü bir uygulama olarak mı yoksa tarayıcı sekmesinde mi çalıştığına bağlı olarak aynı tarayıcıda bile değişebileceğini unutmayın.
Fugu Greetings uygulamasıyla ilgileniyorsanız GitHub'da bu uygulamayı alıp çatallayın.
Chromium ekibi, gelişmiş Fugu API'leri konusunda daha iyi bir deneyim sunmak için yoğun şekilde çalışıyor. Uygulamamı geliştirirken aşamalı geliştirmeyi uygulayarak herkesin iyi ve sağlam bir temel deneyim elde etmesini sağlarken daha fazla web platformu API'sini destekleyen tarayıcılar kullanan kullanıcıların daha da iyi bir deneyim elde etmesini sağlıyorum. Uygulamalarınızda aşamalı geliştirme özelliğini nasıl kullanacağınızı görmeyi sabırsızlıkla bekliyorum.
Teşekkür
Fugu Selamlamaları'na katkıda bulunan Christian Liebel ve Hemanth HM'e minnettarım.
Bu makale, Joe Medley ve Kayce Basques tarafından incelenmiştir.
Jake Archibald, hizmet çalışanı bağlamında dinamik import()
ile ilgili durumu öğrenmeme yardımcı oldu.