İletişim kutusu bileşeni oluşturma

<dialog> öğesiyle renge uyarlanan, duyarlı ve erişilebilir mini ve mega kalıcı öğelerin nasıl oluşturulacağına dair temel bir genel bakış.

Bu gönderide, renge uyum sağlayan tasarımla ilgili düşüncelerimi paylaşmak istiyorum. <dialog> öğesine sahip mini ve mega kalıcı modları. Demoyu deneyin ve şu sayfayı görüntüleyin: kaynak!

Mega ve mini diyalogların açık ve koyu temalarında gösterilmesi.

Video kullanmayı tercih ederseniz bu gönderinin YouTube versiyonunu kullanabilirsiniz:

Genel Bakış

İlgili içeriği oluşturmak için kullanılan <dialog> öğesi, sayfa içi bağlamsal bilgiler veya işlemler için idealdir. Projenin gidişatı boyunca Kullanıcı deneyiminde, birden fazla sayfa yerine aynı sayfa işleminden yararlanılabilir. olabilir: Belki formun küçük olması veya onaylamak veya iptal etmektir.

<dialog> öğesi kısa süre önce tüm tarayıcılarda kararlı hale geldi:

Tarayıcı Desteği

  • 37
  • 79
  • 98
  • 15,4

Kaynak

Öğede bazı şeylerin eksik olduğunu fark ettim. Bu GUI'de Zorluk Geliştirici deneyimini ekliyorum beklediğim öğeler: ek etkinlikler, ışık kapatma, özel animasyonlar ve mini avatar bir seçimdir.

Brüt kar

Bir <dialog> öğesinin temel özellikleri mütevazıdır. Öğe otomatik olarak gizlenir ve içeriğinizle yer paylaşımlı olacak şekilde yerleşik stillere sahiptir.

<dialog>
  …
</dialog>

Bu temel değeri iyileştirebiliriz.

Geleneksel olarak, iletişim öğesi öğesi, kalıcı bir iletişim öğesi ile çok fazla şey paylaşır ve genellikle adlar özellikler birbirinin yerine kullanılabilir. Burada diyalog öğesini kullanma özgürlüğünü kazandım. iletişim kutusu pop-up'ları (mini) ve tam sayfa iletişim kutuları (mega) gösterilir. Adlandırdım her iki diyalog da farklı kullanım alanlarına göre biraz uyarlandı. Türü belirtmenize olanak tanımak için bir modal-mode özelliği ekledim:

<dialog id="MegaDialog" modal-mode="mega"></dialog>
<dialog id="MiniDialog" modal-mode="mini"></dialog>

Açık ve koyu temalardaki mini ve mega iletişim kutularının ekran görüntüsü.

Her zaman değil ancak genellikle bazı bilgileri toplamak için diyalog öğeleri kullanılır daha fazla bilgi edineceksiniz. İletişim kutusu öğelerinin içindeki formlar kullanıma uygun hale getirildi birlikte kullanılabilir. İletişim kutusu içeriğini JavaScript, kullanıcının girdiği verilere erişebilir. Ayrıca, içindeki düğmeler method="dialog" kullanan bir form JavaScript olmadan bir iletişim kutusunu kapatabilir ve dışı verilerdir.

<dialog id="MegaDialog" modal-mode="mega">
  <form method="dialog">
    …
    <button value="cancel">Cancel</button>
    <button value="confirm">Confirm</button>
  </form>
</dialog>

Mega iletişim kutusu

Mega bir iletişim kutusunun içinde üç öğe bulunur: <header>, <article>, ve <footer>. Bunlar anlamsal kapsayıcıların yanı sıra diyaloglarının sunumunu ele alacağız. Üstbilgi, kalıcı öğeyi adlandırıyor ve düğmesini tıklayın. Bu makale, form girişleri ve bilgiler içindir. Altbilgide bir <menu> / işlem düğmeleridir.

<dialog id="MegaDialog" modal-mode="mega">
  <form method="dialog">
    <header>
      <h3>Dialog title</h3>
      <button onclick="this.closest('dialog').close('close')"></button>
    </header>
    <article>...</article>
    <footer>
      <menu>
        <button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
        <button type="submit" value="confirm">Confirm</button>
      </menu>
    </footer>
  </form>
</dialog>

İlk menü düğmesinde autofocus ve onclick satır içi etkinlik işleyicisi. autofocus özelliği odaklanacağım. Bunu en iyi uygulama olarak düşünüyorum. onaylama düğmesine değil, iptal düğmesine basın. Bu, onayın kasten yapılmış olabilir.

Mini iletişim kutusu

Mini iletişim kutusu mega diyaloğa çok benziyor, yalnızca <header> öğesi. Bu, daha küçük ve daha satır içi olmasına olanak tanır.

<dialog id="MiniDialog" modal-mode="mini">
  <form method="dialog">
    <article>
      <p>Are you sure you want to remove this user?</p>
    </article>
    <footer>
      <menu>
        <button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
        <button type="submit" value="confirm">Confirm</button>
      </menu>
    </footer>
  </form>
</dialog>

İletişim öğesi, tüm görüntü alanı öğeleri için güçlü bir temel sağlar. veri ve kullanıcı etkileşimini toplayabilir. Bu temel ihtiyaçlar, bir proje yöneticisinin güçlü etkileşimler oluşturabilirsiniz.

Erişilebilirlik

İletişim öğesinin yerleşik erişilebilirliği çok iyi. Bunları eklemek yerine gibi birçok özellik zaten mevcut.

Odak geri yükleniyor

Yan gezinme bölümü oluşturma bileşenine yer verdikten sonra Bir şeyi doğru şekilde açıp kapatmak, ilgili açılış ve kapanış aşamasına odaklanır düğmelerini kullanın. Yan gezinme paneli açıldığında odak, kapat düğmesine getirilir. Kapat düğmesine basıldığında, odak, düğmeyi açan düğmeye geri döner.

İletişim kutusunda bu, yerleşik varsayılan davranıştır:

Ne yazık ki iletişim kutusunu içeri ve dışarı taşımak istiyorsanız bu işlev kayboldu. JavaScript bölümünde, bu kodu geri yükleyeceğim. işlevi görür.

Odak yakalama

İletişim öğesi, inert sizin için kullanılabilir. inert öncesinde odaklanmayı izlemek için JavaScript kullanılıyordu bir öğe bırakır ve bu noktada araya girer ve onu geri koyar.

Tarayıcı Desteği

  • 102
  • 102
  • 112
  • 15,5

Kaynak

inert tarihinden sonra belgenin tüm bölümleri "dondurulabilir" onlar için çok büyük. hedeflere odaklanmaz veya fare ile etkileşime girer. Hikayeyi dokümanın etkileşimli tek bölümüne yönlendirilir.

Bir öğeyi açma ve otomatik olarak odaklama

Varsayılan olarak, iletişim öğesi odağı ilk odaklanılabilir öğeye atar iletişim kutusu işaretlemesinde. Bu, kullanıcının varsayılan olarak ayarlayabileceği en iyi öğe değilse autofocus özelliğini kullanın. Daha önce de belirttiğim gibi bunun en iyi uygulama olarak bunu onaylama düğmesine değil, iptal düğmesine koyun. Böylece proje daha kasıtlı olarak yapılan onaydır. Yanlışlıkla yapılan bir onay değildir.

Escape tuşuyla kapatma

Rahatsız edici olabilecek bu öğenin kolayca kapatılması önemlidir. Neyse ki iletişim öğesi, escape tuşuna basarak sizin yerinize bu sayede organize etme yükünden kurtulursunuz.

Stiller

İletişim öğesinin stilini ayarlamanın kolay bir yolu ve sabit bir yolu vardır. Kolay yolu, iletişim kutusunun görüntüleme özelliğinin değiştirilip çalışmamasıyla elde edilir sahip olabilirsiniz. Özel animasyonlar sağlamak için iletişim kutusu açılıp kapatılarak display mülkü ve başka alanlar devralınır.

Açık Sahnelerle Stil

Uyarlanabilir renkleri ve genel tasarım tutarlılığını hızlandırmak için CSS değişken kitaplığım Open Props'u getirdi. İçinde ücretsiz sağlanan değişkenlere ek olarak, normalize dosyası ve bazı Her ikisi de Open Props olan buttons isteğe bağlı içe aktarma işlemleri olarak sunar. Bu içe aktarma işlemleri sayesinde, göstermek için çok fazla stile ihtiyaç duymadan diyalog ve demo iyi.

<dialog> öğesinin stilini belirleme

Görüntülü reklam mülküne sahip olma

Bir iletişim öğesinin varsayılan gösterme ve gizleme davranışı, ekranı açar/kapatır mülkü block-none arasında. Maalesef bu videoda animasyon yalnızca içeride, içeride. Hem içeri hem de çıkış animasyonu eklemek istiyorum. İlk adım kendiminkini display mülkü:

dialog {
  display: grid;
}

Görüntülü Reklam Ağı mülkünün değerini değiştirerek ve dolayısıyla sahip olduğunuzda, JavaScript snippet'inin üst kısmında yer alması için çok sayıda stilin uygun kullanıcı deneyimini kolaylaştırma. Öncelikle, iletişim kutusunun varsayılan durumu kapalı. Bu durumu görsel olarak gösterebilir ve iletişim kutusunun şu stillerle etkileşimler alınıyor:

dialog:not([open]) {
  pointer-events: none;
  opacity: 0;
}

Artık iletişim kutusu görünmez ve açık değilken etkileşimde bulunulamaz. Daha sonra İletişim kutusunda inert özelliğini yönetmek için birkaç JavaScript ekleyeceğim. Ayrıca, klavye ve ekran okuyucu kullanıcılarının da gizli iletişim kutusuna erişemezler.

Diyaloğa uyarlanabilir bir renk teması ekleme

Yüzey renklerini gösteren, açık ve koyu temayı gösteren mega iletişim kutusu.

color-scheme, dokümanınızı tarayıcı tarafından sağlanan bir tarayıcıda etkinleştirirken renk temasını açık ve koyu sistem tercihlerine göre özelleştirdim. daha fazla olduğunu düşünelim. Open Props size birkaç yüzey sağlar otomatik olarak uyarlanan renkler açık ve koyu sistem tercihlerini color-scheme kullanmaya benzer. Bu bir tasarımda katmanlar oluşturmak için harika. katman yüzeylerinin bu görünümünü görsel olarak destekler. Arka plan rengi var(--surface-1); üst kısmına taşımak için var(--surface-2) işlevini kullanın:

dialog {
  …
  background: var(--surface-2);
  color: var(--text-1);
}

@media (prefers-color-scheme: dark) {
  dialog {
    border-block-start: var(--border-size-1) solid var(--surface-3);
  }
}

Başlık gibi alt öğeler için daha sonra daha uyarlanabilir renkler eklenir kullanabilirsiniz. Ben bunları bir diyalog öğesi için daha fazla iyi tasarlanmış bir diyalog tasarımı yapmak.

Duyarlı iletişim kutusu boyutlandırma

İletişim kutusu varsayılan olarak boyutunu içeriklerine verir. Bu da genellikle harika. Buradaki amacım max-inline-size okunabilir bir boyuta (--size-content-3 = 60ch) veya görüntü alanı genişliğinin% 90'ına ayarlayın. Bu iletişimin mobil cihazlarda uçtan uca gitmemesini ve görüntülenmeleri zor olabilir. Daha sonra max-block-size Böylece iletişim kutusu sayfanın yüksekliğini aşmaz. Bu, aynı zamanda iletişim kutusunun kaydırılabilir alanının yerini belirtmeniz gerekir (ör. uzun bir metin iletişim kutusu öğesini seçin.

dialog {
  …
  max-inline-size: min(90vw, var(--size-content-3));
  max-block-size: min(80vh, 100%);
  max-block-size: min(80dvb, 100%);
  overflow: hidden;
}

İki kez max-block-size aboneliğimin olduğunu fark ettiniz mi? İlki 80vh, fiziksel bir görüntü alanı birimi. Aslında istediğim, diyaloğu göreli bir akış içinde tutmak, Bu yüzden, ben mantıklı, yeni ve sadece kısmen daha kararlı hale geldiği zaman için ikinci beyanda dvb birimi desteklenmiştir.

Mega iletişim kutusu konumlandırma

Bir iletişim öğesinin konumlandırılmasına yardımcı olması için iki küçük parçalar: tam ekran arka planı ve iletişim kutusu kapsayıcısı. Arka plan, her şeyi kapsayan bir gölge efekti sağlayarak ve arkadaki içeriğe ulaşılamıyor. İletişim kapsayıcısında dilediğiniz zaman bu arka plan üzerinde ortalayarak içeriğin gerektirdiği şekilde şekillendirebilir.

Aşağıdaki stiller, iletişim öğesini pencereye sabitleyerek her bir öğeye uzatarak ve içeriği ortalamak için margin: auto kullanır:

dialog {
  …
  margin: auto;
  padding: 0;
  position: fixed;
  inset: 0;
  z-index: var(--layer-important);
}
Mobil mega iletişim kutusu stilleri

Küçük görüntü alanlarında, bu tam sayfa mega pencereyi biraz farklı şekilde biçimlendiriyorum. İ alt kenar boşluğunu 0 olarak ayarla, bu sayede iletişim kutusu içeriği sayfanın en altına konacak görüntü alanını değiştirebilirsiniz. Birkaç stil ayarlamasıyla iletişim kutusunu hareket sayfasını kullanıcının baş parmaklarına yaklaştırın:

@media (max-width: 768px) {
  dialog[modal-mode="mega"] {
    margin-block-end: 0;
    border-end-end-radius: 0;
    border-end-start-radius: 0;
  }
}

Geliştirici Araçları&#39;nda kenar boşluğu boşluğunun yer paylaşımıyla ilgili ekran görüntüsü 
  hem masaüstü hem mobil mega iletişim kutusunda.

Mini iletişim kutusu konumlandırma

Masaüstü bilgisayar gibi daha büyük bir görüntü alanı kullanırken, mini iletişim kutularını onları çağıran öğedir. Bunun için JavaScript'e ihtiyacım var. Web sitenizin kullandığım teknik buradan Ancak bunun bu makalenin kapsamı dışında olduğunu düşünüyorum. JavaScript olmadan mini iletişim kutusu, mega iletişim kutusu gibi ekranın ortasında görünür.

Çarpıcı hale getirin

Son olarak, iletişim kutusunu çok uzağa uzanmış yumuşak bir yüzey gibi görünecek şekilde zenginleştirin dokunun. Yumuşaklık, iletişim kutusunun köşeleri yuvarlanarak elde edilir. Derinlik, Open Props'un özenle hazırlanmış gölgesinden biriyle elde ediliyor öğeler:

dialog {
  …
  border-radius: var(--radius-3);
  box-shadow: var(--shadow-6);
}

Sözde arka plan öğesini özelleştirme

Arka plan üzerinde çok hafif çalışmayı seçtim. Yalnızca arka plandaki backdrop-filter mega iletişim kutusuna geç:

Tarayıcı Desteği

  • 76
  • 79
  • 103
  • 18

Kaynak

dialog[modal-mode="mega"]::backdrop {
  backdrop-filter: blur(25px);
}

Ayrıca backdrop-filter için bir geçiş yapmayı seçtim. Umarım tarayıcıların arka plan öğesinin ileride geçişine olanak tanır:

dialog::backdrop {
  transition: backdrop-filter .5s ease;
}

Mega iletişim kutusunun, renkli avatarlardan oluşan bulanık bir arka planla yer paylaşımlı şekilde gösterildiği ekran görüntüsü.

Stil ekstraları

Bu bölüme "ekstralar" adını veriyorum. çünkü iletişim öğemle daha çok alakalı daha fazla demo yapmaktır.

Kaydırma kapsamı

İletişim kutusu gösterildiğinde kullanıcı, arkasındaki sayfayı kaydırmaya devam edebilir. istemediğim bir şey var:

Normalde overscroll-behavior her zamanki çözümümdür ancak aboneliğe göre spesifikasyon, üzerinde herhangi bir etkisi yoktur. Çünkü bu bir kaydırma bağlantı noktası değildir, olmadığından emin olun. JavaScript kullanarak bu kılavuzdaki yeni etkinlikler (ör. "closed") ve "opened" seçenekleri yer alır. overflow: hidden veya :has() adlı kullanıcının tüm tarayıcılar:

Tarayıcı Desteği

  • 105
  • 105
  • 121
  • 15,4

Kaynak

html:has(dialog[open][modal-mode="mega"]) {
  overflow: hidden;
}

Artık mega iletişim kutusu açıkken html dokümanında overflow: hidden olur.

<form> düzeni

Paydaşlarla etkileşimi toplamak için çok önemli bir öğe buradan başlık, altbilgi ve görünüm düzenlemelerini makale öğelerinden yararlanabilirsiniz. Bu sayfa düzeniyle, makalenin altını bir kaydırılabilir alan. Bunu başarmak için grid-template-rows. Makale öğesine 1fr verilmiş ve formun kendisi için aynı maksimum değer yüksekliği ile aynı olmalıdır. Bu firma yüksekliğini ve sabit satır boyutunu ayarlamak için makale öğesinin sınırlanmasına ve taştığında kaymasına olanak tanır:

dialog > form {
  display: grid;
  grid-template-rows: auto 1fr auto;
  align-items: start;
  max-block-size: 80vh;
  max-block-size: 80dvb;
}

Geliştirici Araçları&#39;nın satırların üzerinde ızgara düzeni bilgileriyle yer paylaşımlı olarak gösterildiği ekran görüntüsü.

İletişim kutusunun stilini belirleme <header>

Bu öğenin rolü, diyalog içeriği ve teklif için bir başlık sağlamaktır. kolayca bulunabilen bir kapat düğmesi ekleyin. Ayrıca görünmesini sağlamak için bir yüzey rengi de verilmiştir olması gerektiğini unutmayın. Bu gereksinimler, bir flexbox'ın kenarlarına yerleştirilmiş dikey olarak hizalı öğeler ve dolgu ve boşluklar kullanarak başlık ve kapatma düğmelerine biraz alan bırakır:

dialog > form > header {
  display: flex;
  gap: var(--size-3);
  justify-content: space-between;
  align-items: flex-start;
  background: var(--surface-2);
  padding-block: var(--size-3);
  padding-inline: var(--size-5);
}

@media (prefers-color-scheme: dark) {
  dialog > form > header {
    background: var(--surface-1);
  }
}

Chrome Geliştirici Araçları&#39;nın iletişim kutusu başlığında flexbox düzen bilgilerini yer paylaşımlı olarak kullandığı ekran görüntüsü.

Başlığı kapatma düğmesinin stilini belirleme

Demoda Open Props düğmelerini kullandığından kapatma düğmesi özelleştirilmiştir şu şekilde yuvarlak, simge merkezli bir düğmeye dönüşür:

dialog > form > header > button {
  border-radius: var(--radius-round);
  padding: .75ch;
  aspect-ratio: 1;
  flex-shrink: 0;
  place-items: center;
  stroke: currentColor;
  stroke-width: 3px;
}

Chrome Geliştirici Araçları&#39;nın başlık kapat düğmesi için boyut ve dolgu bilgilerini yer paylaşımlı olarak kullandığı ekran görüntüsü.

İletişim kutusunun stilini belirleme <article>

Makale öğesinin bu iletişim kutusunda özel bir rolü vardır: uzun veya uzun bir iletişim kutusundaysa kaydırılamaz.

Bunu sağlamak için üst form öğesi, dönüşüm izleme için Bu makale öğesinin kendisi çok uzun. Kaydırma çubuklarının yalnızca gerektiğinde gösterileceği şekilde overflow-y: auto özelliğini ayarlayın. içinde overscroll-behavior: contain ile kaydırma içerir ve özel sunu stilleri olacaktır:

dialog > form > article {
  overflow-y: auto; 
  max-block-size: 100%; /* safari */
  overscroll-behavior-y: contain;
  display: grid;
  justify-items: flex-start;
  gap: var(--size-3);
  box-shadow: var(--shadow-2);
  z-index: var(--layer-1);
  padding-inline: var(--size-5);
  padding-block: var(--size-3);
}

@media (prefers-color-scheme: light) {
  dialog > form > article {
    background: var(--surface-1);
  }
}

Altbilginin rolü, işlem düğmelerinin menüleri içermesidir. Flexbox, Flexbox'ın kullanıldığı içeriği altbilgi satır içi ekseninin sonuna hizalayın ve daha sonra, düğmelere biraz alan tanıyın.

dialog > form > footer {
  background: var(--surface-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--size-3);
  justify-content: space-between;
  align-items: flex-start;
  padding-inline: var(--size-5);
  padding-block: var(--size-3);
}

@media (prefers-color-scheme: dark) {
  dialog > form > footer {
    background: var(--surface-1);
  }
}

Chrome Geliştirici Araçları&#39;nın altbilgi öğesinde flexbox düzen bilgilerini yer paylaşımlı olarak kullandığı ekran görüntüsü.

menu öğesi, iletişim kutusuna ilişkin işlem düğmelerini içermek için kullanılır. Sarmalama kullanır Düğmeler arasında boşluk sağlamak için gap ile flexbox düzeni. Menü öğeleri <ul> gibi bir dolgu içerir. Ayrıca, ihtiyacım olmadığı için bu stili kaldırıyorum.

dialog > form > footer > menu {
  display: flex;
  flex-wrap: wrap;
  gap: var(--size-3);
  padding-inline-start: 0;
}

dialog > form > footer > menu:only-child {
  margin-inline-start: auto;
}

Chrome Geliştirici Araçları&#39;nın altbilgi menü öğelerinde flexbox bilgilerini yer paylaşımlı olarak kullandığı ekran görüntüsü.

Animasyon

İletişim kutusu öğeleri, pencereye girip çıktıkları için genellikle canlandırmalı olur. Diyaloglara bu giriş ve çıkış için destekleyici hareketler sunmak kullanıcıların odaklanmasını sağlamak.

Normalde iletişim kutusu öğesi yalnızca animasyon içine eklenebilir, dışarı çıkarılamaz. Çünkü tarayıcı, öğedeki display özelliğini açar. Önceki videolarda, kılavuz ekranı ızgaraya ayarlayın ve hiçbir zaman "yok" olarak ayarlama. Bu sayede, ekibinizle beraber animasyon içerir.

Open Props oyunlarının birçok animasyon karesi animasyonların kullanılmasını sağlayın; ve okunaklı hale getirebilirsiniz. Burada animasyon hedefleri ve katmanlı şu yaklaşımı benimsedim:

  1. Azaltılmış hareket, varsayılan geçiştir. Basit bir opaklık giderek azalır.
  2. Hareket yeterliyse kaydırma ve ölçek animasyonları eklenir.
  3. Mega iletişim için duyarlı mobil düzen, dışarı kayacak şekilde ayarlandı.

Güvenli ve anlamlı bir varsayılan geçiş

Open Props ekran görüntüsünde azalan ve dönüşler için animasyon kareleri bulunsa da bunu katmanlı geçiş yaklaşımını kullanarak varsayılan olarak animasyon karesi gerçekleşebilir. Daha önceki videolarda diyaloğun görünürlüğünü opaklık, [open] özelliğine bağlı olarak 1 veya 0 düzenlenir. Alıcı: %0 ve %100 arasında bir geçiş olursa, tarayıcıya ne kadar ve ne tür istediğiniz yumuşatmayı tercih edebilirsiniz:

dialog {
  transition: opacity .5s var(--ease-3);
}

Geçişe hareket ekleme

Kullanıcı hareketi kabul ediyorsa hem mega hem de mini iletişim kutuları kaymalıdır izin verilir ve çıkış olarak ölçeklendirilir. Bunu başarmak için prefers-reduced-motion medya sorgusu ve birkaç Open Prop:

@media (prefers-reduced-motion: no-preference) {
  dialog {
    animation: var(--animation-scale-down) forwards;
    animation-timing-function: var(--ease-squish-3);
  }

  dialog[open] {
    animation: var(--animation-slide-in-up) forwards;
  }
}
.

Çıkış animasyonunu mobil cihazlar için uyarlama

Stil bölümünün başlarında mega diyalog stili, mobil cihazlar için sanki küçük bir kağıt parçasının kaydığı gibi bir işlem sayfasına ekranın alt kısmından yukarı bakıyor ve hâlâ alta sabitlenmiş durumda. Ölçek çıkış animasyonu, bu yeni tasarıma iyi uymamaktadır ve bunu, bazı medya sorguları ve bazı Open Prop'ler:

@media (prefers-reduced-motion: no-preference) and @media (max-width: 768px) {
  dialog[modal-mode="mega"] {
    animation: var(--animation-slide-out-down) forwards;
    animation-timing-function: var(--ease-squish-2);
  }
}

JavaScript

JavaScript'e eklenecek pek çok şey vardır:

// dialog.js
export default async function (dialog) {
  // add light dismiss
  // add closing and closed events
  // add opening and opened events
  // add removed event
  // removing loading attribute
}

Bu eklemeler, ışığın kapatılması (iletişim kutusunu arka plan), animasyonu ve diğer etkinlikleri içeren olduğunu unutmayın.

Işık kapatma ekleniyor

Bu görev basittir ve gözünüzden kaçan bir diyalog öğesine animasyon kullanılır. Etkileşim, iletişim kutusundaki tıklamaların izlenmesiyle gerçekleştirilir öğesi oluşturmak için bir etkinlik şampuan yalnızca neyin tıklandığını değerlendirecek ve close() en üstteki öğe ise:

export default async function (dialog) {
  dialog.addEventListener('click', lightDismiss)
}

const lightDismiss = ({target:dialog}) => {
  if (dialog.nodeName === 'DIALOG')
    dialog.close('dismiss')
}

Uyarı dialog.close('dismiss'). Etkinlik çağrılır ve bir dize sağlanır. Bu dize, iletişim kutusu kapatıldı. Her telefon ettiğimde de kapattığım dizeleri çeşitli düğmelerden işlevini kullanarak, uygulamama kullanıcı etkileşimi.

Kapanış ve kapanış etkinlikleri ekleme

İletişim öğesi bir kapatma etkinliğiyle gelir: iletişim kutusu close() işlevi çağrılır. Bu öğeyi canlandırdığımız için animasyondan önce ve sonra etkinlikler olması güzel. veya iletişim formunu sıfırlayın. Burada, Kapatılan iletişim kutusunda inert özelliği var ve demoda bunu değiştirmek için Kullanıcı yeni bir resim gönderdiğinde avatar listesine eklenir.

Bunu elde etmek için closing ve closed adında iki yeni etkinlik oluşturun. Sonra yerleşik kapatma etkinliğini dinleyin. Buradan iletişim kutusunu inert ve closing etkinliğini gönderin. Bir sonraki görev, animasyonların ve geçişlerin iletişim kutusunda çalışmasını bitirmek, ardından closed etkinliği.

const dialogClosingEvent = new Event('closing')
const dialogClosedEvent  = new Event('closed')

export default async function (dialog) {
  …
  dialog.addEventListener('close', dialogClose)
}

const dialogClose = async ({target:dialog}) => {
  dialog.setAttribute('inert', '')
  dialog.dispatchEvent(dialogClosingEvent)

  await animationsComplete(dialog)

  dialog.dispatchEvent(dialogClosedEvent)
}

const animationsComplete = element =>
  Promise.allSettled(
    element.getAnimations().map(animation => 
      animation.finished))

Kısa mesaj oluşturma bölümünde de kullanılan animationsComplete işlevi bileşenine göre bir vaat döndürür. animasyon ve geçiş taahhütlerinin tamamlanmasına yardımcı olun. Bu nedenle dialogClose eş zamansızdır fonksiyon; o zaman await ve emin adımlarla kapalı etkinliğe devam etmek ister misiniz?

Açılış ve açık etkinlikler ekleme

Yerleşik iletişim öğesi kolayca eklenemeyeceği için bu etkinlikleri eklemek tıpkı kapanışta olduğu gibi açık bir etkinlik sağlar. Ben MutationObserver seçerek iletişim kutusunun özellikleriyle ilgili anlamlı analizler elde edebilirsiniz. Bu gözlemcide Açık özellikteki değişiklikleri gözlemleyip özel etkinlikleri yöneteceğim buna göre hazırlar.

Kapanış ve kapanış etkinliklerimize benzer şekilde iki yeni etkinlik oluşturun. opening ve opened. Daha önce diyaloğun kapatılmasını dinlediğimiz platform Bu kez, diyalogun durumunu izlemek için oluşturulmuş bir mutasyon gözlemleyicisi özellikleri hakkında daha fazla bilgi edinin.

…
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent  = new Event('opened')

export default async function (dialog) {
  …
  dialogAttrObserver.observe(dialog, { 
    attributes: true,
  })
}

const dialogAttrObserver = new MutationObserver((mutations, observer) => {
  mutations.forEach(async mutation => {
    if (mutation.attributeName === 'open') {
      const dialog = mutation.target

      const isOpen = dialog.hasAttribute('open')
      if (!isOpen) return

      dialog.removeAttribute('inert')

      // set focus
      const focusTarget = dialog.querySelector('[autofocus]')
      focusTarget
        ? focusTarget.focus()
        : dialog.querySelector('button').focus()

      dialog.dispatchEvent(dialogOpeningEvent)
      await animationsComplete(dialog)
      dialog.dispatchEvent(dialogOpenedEvent)
    }
  })
})

İletişim kutusu görüntülendiğinde mutasyon gözlemleyicisi geri çağırma işlevi özellikleri değiştirilir ve değişikliklerin listesi bir dizi olarak gösterilir. Yineleme yap özellik değişir ve attributeName öğesinin açık olup olmadığına bakar. Ardından, öğenin özelliğe sahip olup olmadığı bilgisi: Bu, iletişim kutusunun hale gelmiştir. Açılmışsa inert özelliğini kaldırın, odağı ayarlayın başka bir öğeden birine autofocus veya iletişim kutusundaki ilk button öğesi. Son olarak, ve kapalı etkinlik varsa, açılış etkinliğini hemen gönderin, animasyonların gelmesini bekleyin ve açılan etkinliği gönderin.

Kaldırılan bir etkinliği ekleme

Tek sayfalık uygulamalarda, iletişim kutuları genellikle rotalara göre eklenip kaldırılır beyanda bulunmanız gerekir. Bu araç, etkinlikleri temizlemek veya verilerini de görebilirsiniz.

Bunu başka bir mutasyon gözlemcisiyle başarabilirsiniz. Bu sefer, özellikleri gözlemlediğimizde, vücudun alt öğelerini gözlemleyeceğiz öğesine dokunun ve iletişim kutusu öğelerinin kaldırılmasını bekleyin.

…
const dialogRemovedEvent = new Event('removed')

export default async function (dialog) {
  …
  dialogDeleteObserver.observe(document.body, {
    attributes: false,
    subtree: false,
    childList: true,
  })
}

const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
  mutations.forEach(mutation => {
    mutation.removedNodes.forEach(removedNode => {
      if (removedNode.nodeName === 'DIALOG') {
        removedNode.removeEventListener('click', lightDismiss)
        removedNode.removeEventListener('close', dialogClose)
        removedNode.dispatchEvent(dialogRemovedEvent)
      }
    })
  })
})

Alt öğeler eklendiğinde veya kaldırıldığında mutasyon gözlemleyici geri çağırması çağrılır . İzlenen belirli mutasyonlar Şuna sahip removedNodes: nodeName/ iletişim kutusu. İletişim kutusu kaldırıldıysa tıklama ve kapatma etkinlikleri yer açın ve kaldırılan özel etkinlik gönderilir.

Yükleme özelliği kaldırılıyor

İletişim kutusu animasyonunun iletişim kutusuna bir yükleme özelliği eklenmiştir. İlgili içeriği oluşturmak için kullanılan aşağıdaki komut dosyası, iletişim kutusu animasyonlarının çalışmasının bitmesini bekler ve belirtir. Artık diyaloğun içindeki animasyonlar serbestçe açılabilir. Ayrıca, başka türlü dikkat dağıtan bir animasyonu etkili şekilde gizlemiştir.

export default async function (dialog) {
  …
  await animationsComplete(dialog)
  dialog.removeAttribute('loading')
}

Sayfa yüklemede animasyon karesi animasyonlarını engelleme sorunu hakkında daha fazla bilgi edinin. burada bulabilirsiniz.

Hepsi bir arada

Her bölümü açıkladığımıza göre dialog.js buradan ayrı ayrı:

// custom events to be added to <dialog>
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent  = new Event('closed')
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent  = new Event('opened')
const dialogRemovedEvent = new Event('removed')

// track opening
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
  mutations.forEach(async mutation => {
    if (mutation.attributeName === 'open') {
      const dialog = mutation.target

      const isOpen = dialog.hasAttribute('open')
      if (!isOpen) return

      dialog.removeAttribute('inert')

      // set focus
      const focusTarget = dialog.querySelector('[autofocus]')
      focusTarget
        ? focusTarget.focus()
        : dialog.querySelector('button').focus()

      dialog.dispatchEvent(dialogOpeningEvent)
      await animationsComplete(dialog)
      dialog.dispatchEvent(dialogOpenedEvent)
    }
  })
})

// track deletion
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
  mutations.forEach(mutation => {
    mutation.removedNodes.forEach(removedNode => {
      if (removedNode.nodeName === 'DIALOG') {
        removedNode.removeEventListener('click', lightDismiss)
        removedNode.removeEventListener('close', dialogClose)
        removedNode.dispatchEvent(dialogRemovedEvent)
      }
    })
  })
})

// wait for all dialog animations to complete their promises
const animationsComplete = element =>
  Promise.allSettled(
    element.getAnimations().map(animation => 
      animation.finished))

// click outside the dialog handler
const lightDismiss = ({target:dialog}) => {
  if (dialog.nodeName === 'DIALOG')
    dialog.close('dismiss')
}

const dialogClose = async ({target:dialog}) => {
  dialog.setAttribute('inert', '')
  dialog.dispatchEvent(dialogClosingEvent)

  await animationsComplete(dialog)

  dialog.dispatchEvent(dialogClosedEvent)
}

// page load dialogs setup
export default async function (dialog) {
  dialog.addEventListener('click', lightDismiss)
  dialog.addEventListener('close', dialogClose)

  dialogAttrObserver.observe(dialog, { 
    attributes: true,
  })

  dialogDeleteObserver.observe(document.body, {
    attributes: false,
    subtree: false,
    childList: true,
  })

  // remove loading attribute
  // prevent page load @keyframes playing
  await animationsComplete(dialog)
  dialog.removeAttribute('loading')
}

dialog.js modülünü kullanma

Modülden dışa aktarılan işlevin bir iletişim kutusu çağrılmasını ve iletilmesini bekler öğesi ekleyin:

import GuiDialog from './dialog.js'

const MegaDialog = document.querySelector('#MegaDialog')
const MiniDialog = document.querySelector('#MiniDialog')

GuiDialog(MegaDialog)
GuiDialog(MiniDialog)

Aynı şekilde iki iletişim kutusu da ışık kapatma, animasyon ve daha fazla etkinlikle ilgili bilgi sahibi olabilirsiniz.

Yeni özel etkinlikleri dinleme

Yükseltilen her iletişim öğesi artık aşağıdaki gibi beş yeni etkinliği dinleyebilir:

MegaDialog.addEventListener('closing', dialogClosing)
MegaDialog.addEventListener('closed', dialogClosed)

MegaDialog.addEventListener('opening', dialogOpening)
MegaDialog.addEventListener('opened', dialogOpened)

MegaDialog.addEventListener('removed', dialogRemoved)

Aşağıda, bu etkinliklerin işlenmesiyle ilgili iki örnek verilmiştir:

const dialogOpening = ({target:dialog}) => {
  console.log('Dialog opening', dialog)
}

const dialogClosed = ({target:dialog}) => {
  console.log('Dialog closed', dialog)
  console.info('Dialog user action:', dialog.returnValue)

  if (dialog.returnValue === 'confirm') {
    // do stuff with the form values
    const dialogFormData = new FormData(dialog.querySelector('form'))
    console.info('Dialog form data', Object.fromEntries(dialogFormData.entries()))

    // then reset the form
    dialog.querySelector('form')?.reset()
  }
}

İletişim öğesiyle oluşturduğum demoda bu kapalı etkinliği kullanıp form verilerini tıklayarak listeye yeni bir avatar öğesi ekleyin. Zamanlamanın iyi olması iletişim kutusunun çıkış animasyonunu tamamladığını ve ardından bazı komut dosyalarının animasyon simgesini tıklayın. Yeni etkinlikler sayesinde kullanıcı deneyimini düzenlemek olabilir.

dialog.returnValue dikkati: Bu kod, close() iletişim kutusu çağrıldı. dialogClosed etkinliğinde çok önemli olan iletişimin kapatılıp kapatılmadığını, iptal edilip edilmediğini veya onaylanıp onaylanmadığını öğrenebilirsiniz. Onaylanırsa komut dosyası, form değerlerini alıp formu sıfırlar. Sıfırlama işlemi, iletişim kutusu tekrar gösterildiğinde boş ve yeni gönderim için hazırdır.

Sonuç

Şimdi bunu nasıl yaptığımı öğrendiğinize göre siz nasıl ‽ 🙂

Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim.

Bir demo oluşturup beni tweet'le bağlantıları eklerim aşağıdaki topluluk remiksleri bölümüne gidin!

Topluluk remiksleri

Kaynaklar