Anahtar bileşeni oluşturma

Duyarlı ve erişilebilir bir anahtar bileşeni oluşturmaya dair temel bilgiler.

Bu yayında, anahtar bileşenlerini oluşturmanın bir yolu hakkındaki düşüncelerimi paylaşmak istiyorum. Demoyu deneyin.

Demo

Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:

Genel Bakış

Anahtar, onay kutusuna benzer şekilde çalışır ancak açık ve kapalı boole durumlarını açıkça gösterir.

Bu demodaki işlevlerin çoğunda <input type="checkbox" role="switch"> kullanılır. Bu da, CSS veya JavaScript'in tamamen işlevsel ve erişilebilir olmasına gerek olmaması avantajına sahiptir. CSS'nin yüklenmesi, sağdan sola yazılan diller, dikeylik, animasyon ve daha fazlası için destek sağlar. JavaScript'i yüklemek, anahtarı sürüklenebilir ve somut hale getirir.

Özel özellikler

Aşağıdaki değişkenler, anahtarın çeşitli bölümlerini ve seçeneklerini temsil eder. Üst düzey sınıf olarak .gui-switch, bileşen alt öğeleri genelinde kullanılan özel özellikleri ve merkezi özelleştirme için giriş noktalarını içerir.

Parça

Uzunluk (--track-size), dolgu ve iki renk:

.gui-switch {
  --track-size: calc(var(--thumb-size) * 2);
  --track-padding: 2px;

  --track-inactive: hsl(80 0% 80%);
  --track-active: hsl(80 60% 45%);

  --track-color-inactive: var(--track-inactive);
  --track-color-active: var(--track-active);

  @media (prefers-color-scheme: dark) {
    --track-inactive: hsl(80 0% 35%);
    --track-active: hsl(80 60% 60%);
  }
}

Küçük resim

Boyut, arka plan rengi ve etkileşim renkleri vurgulanır:

.gui-switch {
  --thumb-size: 2rem;
  --thumb: hsl(0 0% 100%);
  --thumb-highlight: hsl(0 0% 0% / 25%);

  --thumb-color: var(--thumb);
  --thumb-color-highlight: var(--thumb-highlight);

  @media (prefers-color-scheme: dark) {
    --thumb: hsl(0 0% 5%);
    --thumb-highlight: hsl(0 0% 100% / 25%);
  }
}

Az hareket

Net bir takma ad eklemek ve tekrarı azaltmak için, PostCSS eklentisi ile özel bir mülke azaltılmış hareket tercihi kullanıcı medya sorgusu eklenebilir. Bu işlem, Media Queries 5'teki taslak spesifikasyonu temel alınarak yapılır:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

Brüt kar

Onay kutusu ve etiket ilişkilendirmesi belirsizliğini önlemek için <input type="checkbox" role="switch"> öğemi bir <label> ile sarmalamayı tercih ettim. Aynı zamanda kullanıcıya, girişi açıp kapatabilmek için etiketle etkileşimde bulunma olanağı da verdim.

Doğal, stil uygulanmamış bir etiket ve onay kutusu.

<label for="switch" class="gui-switch">
  Label text
  <input type="checkbox" role="switch" id="switch">
</label>

<input type="checkbox">, önceden oluşturulmuş bir API ve durum ile birlikte sunulur. Tarayıcı, checked mülkünü ve oninput ile onchanged gibi giriş etkinliklerini yönetir.

Düzenler

Flexbox, grid ve özel özellikler, bu bileşenin stillerinin korunmasında kritik öneme sahiptir. Değerleri merkezileştirir, aksi takdirde belirsiz olan hesaplamalara veya alanlara ad verir ve kolay bileşen özelleştirmeleri için küçük bir özel mülk API'si etkinleştirir.

.gui-switch

Geçiş için üst düzey düzen, flexbox'tur. .gui-switch sınıfı, çocukların düzenleri hesaplamak için kullandığı özel ve herkese açık özel mülkleri içerir.

Yatay bir etiket ve anahtarı kapsayan Flexbox DevTools, bunların alan dağılımını gösterir.

.gui-switch {
  display: flex;
  align-items: center;
  gap: 2ch;
  justify-content: space-between;
}

Flexbox düzenini genişletmek ve değiştirmek, herhangi bir flexbox düzenini değiştirmeye benzer. Örneğin, bir anahtarın üzerine veya altına etiket koymak ya da flex-direction:

Dikey bir etiket ve anahtarın üzerine yerleştirilmiş Flexbox DevTools.

<label for="light-switch" class="gui-switch" style="flex-direction: column">
  Default
  <input type="checkbox" role="switch" id="light-switch">
</label>

Parça

Onay kutusu girişi, normal appearance: checkbox boyutu kaldırılarak ve kendi boyutu sağlanarak anahtar yolu olarak biçimlendirilir:

Geçiş kanalını kaplayan Grid DevTools, adlandırılmış ızgara kanal alanlarını &quot;track&quot; adıyla gösterir.

.gui-switch > input {
  appearance: none;

  inline-size: var(--track-size);
  block-size: var(--thumb-size);
  padding: var(--track-padding);

  flex-shrink: 0;
  display: grid;
  align-items: center;
  grid: [track] 1fr / [track] 1fr;
}

Parça, küçük resim için tek tek tek hücreli bir ızgara parça alanı da oluşturur.

Küçük resim

appearance: none stili, tarayıcı tarafından sağlanan görsel onay işaretini de kaldırır. Bu bileşen, bu görsel göstergenin yerini almak için girişte bir sözde öğe ve :checked sözde sınıf kullanır.

Başparmak, input[type="checkbox"] öğesine bağlı bir sözde öğe alt öğesidir ve track ızgara alanını talep ederek kanalın altında değil üstünde yığınlanır:

Sanal öğe başparmağını CSS ızgarasına yerleştirilmiş olarak gösteren DevTools.

.gui-switch > input::before {
  content: "";
  grid-area: track;
  inline-size: var(--thumb-size);
  block-size: var(--thumb-size);
}

Stiller

Özel özellikler; renk şemalarına, sağdan sola dillere ve hareket tercihlerine uyum sağlayan çok yönlü bir anahtar bileşeni sağlar.

Anahtar ve durumları için açık ve koyu temanın yan yana karşılaştırması.

Dokunmatik etkileşim stilleri

Mobil cihazlarda tarayıcılar, etiketlere ve girişlere dokunma vurguları ve metin seçim özellikleri ekler. Bu sorunlar, bu geçiş için gereken stil ve görsel etkileşim geri bildirimini olumsuz yönde etkiledi. Birkaç satır CSS ile bu efektleri kaldırabilir ve kendi cursor: pointer stilimi ekleyebilirim:

.gui-switch {
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

Bu stillerin kaldırılması, değerli görsel etkileşim geri bildirimi olabileceği için her zaman tavsiye edilmez. Kaldırırsanız özel alternatifler sunduğunuzdan emin olun.

Parça

Bu öğenin stilleri, çoğunlukla şekli ve rengiyle ilgilidir. Bu stillere, kademeli aracılığıyla üst .gui-switch öğesinden erişir.

Özel parça boyutları ve renklerine sahip varyantları değiştirin.

.gui-switch > input {
  appearance: none;
  border: none;
  outline-offset: 5px;
  box-sizing: content-box;

  padding: var(--track-padding);
  background: var(--track-color-inactive);
  inline-size: var(--track-size);
  block-size: var(--thumb-size);
  border-radius: var(--track-size);
}

Geçiş yolu için dört özel mülkten çok çeşitli özelleştirme seçenekleri elde edilebilir. appearance: none, tüm tarayıcılarda onay kutusunun kenarlıklarını kaldırmadığı için border: none eklenir.

Küçük resim

Küçük resim öğesi zaten sağ tarafta track ancak daire stillerine ihtiyacı var:

.gui-switch > input::before {
  background: var(--thumb-color);
  border-radius: 50%;
}

Daire başparmak sözde öğesinin vurgulandığı DevTools gösterilmektedir.

Etkileşim

Fareyle üzerine gelmeyle vurgulanan öğeleri ve başparmak konumu değişikliklerini gösterecek etkileşimlere hazırlanmak için özel mülkleri kullanın. Hareket veya fareyle üzerine gelme stillerini geçirmeden önce kullanıcının tercihi de kontrol edilir.

.gui-switch > input::before {
  box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight);

  @media (--motionOK) { & {
    transition:
      transform var(--thumb-transition-duration) ease,
      box-shadow .25s ease;
  }}
}

Başparmak konumu

Özel mülkler, başparmağı parçaya yerleştirmek için tek bir kaynak mekanizması sağlar. Başparmak kaydırma çubuğunu doğru şekilde kaydırarak kaydırma çubuğu içinde tutabilmek için hesaplamalarda kullanacağımız kaydırma çubuğu ve başparmak boyutları (0% ve 100%) mevcuttur.

input öğesi --thumb-position konum değişkenine sahiptir ve başparmak sözde öğesi bunu translateX konumu olarak kullanır:

.gui-switch > input {
  --thumb-position: 0%;
}

.gui-switch > input::before {
  transform: translateX(var(--thumb-position));
}

Artık CSS'deki --thumb-position ve onay kutusu öğelerinde sağlanan sözde sınıfları değiştirebiliriz. Bu öğede transition: transform var(--thumb-transition-duration) ease koşullu olarak daha önce ayarlandığından, aşağıdaki değişiklikler değiştirildiğinde animasyonlu olabilir:

/* positioned at the end of the track: track length - 100% (thumb width) */
.gui-switch > input:checked {
  --thumb-position: calc(var(--track-size) - 100%);
}

/* positioned in the center of the track: half the track - half the thumb */
.gui-switch > input:indeterminate {
  --thumb-position: calc(
    (var(--track-size) / 2) - (var(--thumb-size) / 2)
  );
}

Bu bağımsız düzenlemenin işe yaradığını düşünmüştüm. Küçük resim öğesi yalnızca bir stil (translateX konumu) ile ilgilenir. Bu girdi, tüm karmaşıklığı ve hesaplamaları yönetebilir.

Sektör

Destek, input öğesine CSS dönüşümleriyle dönme ekleyen bir değiştirici sınıf -vertical ile sağlandı.

3D döndürülmüş bir öğe, bileşenin toplam yüksekliğini değiştirmez. Bu da blok düzenini bozabilir. --track-size ve --track-padding değişkenlerini kullanarak bunu hesaba katın. Dikey bir düğmenin düzende beklendiği gibi akması için gereken minimum alan miktarını hesaplayın:

.gui-switch.-vertical {
  min-block-size: calc(var(--track-size) + calc(var(--track-padding) * 2));

  & > input {
    transform: rotate(-90deg);
  }
}

(RTL) sağdan sola

CSS uzmanı bir arkadaşım olan Elad Schecter ile birlikte, tek bir değişkeni değiştirerek sağdan sola yazılan dilleri işleyen CSS dönüşümlerini kullanarak kaydırılabilir bir yan menü prototipini oluşturduk. Bunu, CSS'de mantıksal özellik dönüşümleri olmadığı ve hiçbir zaman olmayabileceği için yaptık. Elad, mantıksal dönüştürme işlemleri için kendi özel mantığımızın tek bir konumda yönetilmesine olanak tanımak amacıyla yüzdeleri tersine çevirmek için özel bir mülk değeri kullanma fikrini ortaya attı. Bu geçişte aynı tekniği kullandım ve çok başarılı olduğunu düşünüyorum:

.gui-switch {
  --isLTR: 1;

  &:dir(rtl) {
    --isLTR: -1;
  }
}

Düzenimiz varsayılan olarak soldan sağa doğru olduğundan --isLTR adlı özel özellik başlangıçta 1 değerini alır. Bu, true değerine sahip olduğu anlamına gelir. Ardından, bileşen sağdan sola düzen içinde olduğunda :dir() CSS sözde sınıfını kullanarak değer -1 olarak ayarlanır.

Bir dönüştürme işleminin içindeki calc() içinde kullanarak --isLTR'ü harekete geçirin:

.gui-switch.-vertical > input {
  transform: rotate(-90deg);
  transform: rotate(calc(90deg * var(--isLTR) * -1));
}

Artık dikey anahtarın döndürülmesi, sağdan sola düzenin gerektirdiği karşı taraf konumu dikkate alır.

Küçük resim öğesi üzerindeki translateX dönüşümlerinin de karşı taraf şartını dikkate alarak güncellenmesi gerekir:

.gui-switch > input:checked {
  --thumb-position: calc(var(--track-size) - 100%);
  --thumb-position: calc((var(--track-size) - 100%) * var(--isLTR));
}

.gui-switch > input:indeterminate {
  --thumb-position: calc(
    (var(--track-size) / 2) - (var(--thumb-size) / 2)
  );
  --thumb-position: calc(
   ((var(--track-size) / 2) - (var(--thumb-size) / 2))
    * var(--isLTR)
  );
}

Bu yaklaşım, mantıksal CSS dönüştürme işlemleri gibi bir kavramla ilgili tüm ihtiyaçları çözmek için işe yaramasa da birçok kullanım alanı için bazı DRY ilkeleri sunar.

Eyaletler

Yerleşik input[type="checkbox"]'ü kullanmak için :checked, :disabled, :indeterminate ve :hover gibi çeşitli durumları ele almak gerekir. :focus, yalnızca ofsetinde ayarlama yapılarak kasıtlı olarak olduğu gibi bırakıldı. Odak halkası Firefox ve Safari'de harika görünüyordu:

Firefox ve Safari&#39;de bir anahtara odaklanan odak halkasının ekran görüntüsü.

Kontrol edildi

<label for="switch-checked" class="gui-switch">
  Default
  <input type="checkbox" role="switch" id="switch-checked" checked="true">
</label>

Bu eyalet, on durumunu temsil eder. Bu durumda, giriş "parça" arka planı etkin renge, başparmak konumu ise "sona" ayarlanır.

.gui-switch > input:checked {
  background: var(--track-color-active);
  --thumb-position: calc((var(--track-size) - 100%) * var(--isLTR));
}

Devre dışı

<label for="switch-disabled" class="gui-switch">
  Default
  <input type="checkbox" role="switch" id="switch-disabled" disabled="true">
</label>

:disabled düğmesi yalnızca görsel olarak farklı görünmekle kalmaz, öğeyi de değiştirilemez hale getirir. Etkileşimin değiştirilemezliği tarayıcıdan bağımsızdır ancak görsel durumların appearance: none kullanılması nedeniyle stillere ihtiyacı vardır.

.gui-switch > input:disabled {
  cursor: not-allowed;
  --thumb-color: transparent;

  &::before {
    cursor: not-allowed;
    box-shadow: inset 0 0 0 2px hsl(0 0% 100% / 50%);

    @media (prefers-color-scheme: dark) { & {
      box-shadow: inset 0 0 0 2px hsl(0 0% 0% / 50%);
    }}
  }
}

Devre dışı, işaretli ve işaretsiz durumlarda koyu stildeki anahtar.

Hem devre dışı hem de işaretli duruma sahip koyu ve açık temalara ihtiyaç duyduğundan bu durum biraz karmaşıktır. Stil kombinasyonlarının bakım yükünü hafifletmek amacıyla bu durumlar için stil olarak minimal stiller seçtim.

Belirsiz

Genellikle unutulan bir durum da :indeterminate'dir. Bu durumda onay kutusunun işareti kaldırılmamış veya işaretlenmemiştir. Bu eğlenceli bir durum, davet edici ve mütevazı. Boole durumlarının, aralarında gizli durumlar olabileceğini hatırlatmak isteriz.

Onay kutusunu belirsiz olarak ayarlamak zordur. Bu ayarı yalnızca JavaScript yapabilir:

<label for="switch-indeterminate" class="gui-switch">
  Indeterminate
  <input type="checkbox" role="switch" id="switch-indeterminate">
  <script>document.getElementById('switch-indeterminate').indeterminate = true</script>
</label>

Kararsızlığı belirtmek için parça küçük resminin ortada olduğu belirsiz durum.

Bu eyalet benim için mütevazı ve davetkar olduğundan, anahtar başparmağı konumunu ortada yerleştirmek uygun geldi:

.gui-switch > input:indeterminate {
  --thumb-position: calc(
    calc(calc(var(--track-size) / 2) - calc(var(--thumb-size) / 2))
    * var(--isLTR)
  );
}

İmleçle üzerine gelin

Fareyle üzerine gelme etkileşimleri, bağlı kullanıcı arayüzü için görsel destek sağlamalı ve ayrıca etkileşimli kullanıcı arayüzüne yön vermelidir. Bu anahtar, etiket veya giriş üzerine gelindiğinde baş parmağı yarı şeffaf bir halkayla vurgular. Bu fareyle üzerine gelme animasyonu, etkileşimli küçük resim öğesine yönlendirme sağlar.

"Vurgulama" efekti box-shadow ile yapılır. Fareyle devre dışı bırakılmamış bir girişin üzerine geldiğinizde --highlight-size boyutunu artırın. Kullanıcı hareketi kabul ediyorsa box-shadow'ü büyüterek geçiş yaparız. Kullanıcı hareketi kabul etmiyorsa öne çıkan anlar anında gösterilir:

.gui-switch > input::before {
  box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight);

  @media (--motionOK) { & {
    transition:
      transform var(--thumb-transition-duration) ease,
      box-shadow .25s ease;
  }}
}

.gui-switch > input:not(:disabled):hover::before {
  --highlight-size: .5rem;
}

JavaScript

Anahtar arayüzü, fiziksel bir arayüzü taklit etmeye çalışırken (özellikle de bir kanalın içinde daire bulunan bu tür) bana tuhaf gelebilir. iOS, anahtarlarıyla bu konuda doğru bir iş çıkarmış. Anahtarları yana doğru sürükleyebilirsiniz ve bu seçeneğe sahip olmak çok tatmin edici. Buna karşılık, sürükleme hareketi yapılırsa ve hiçbir şey olmazsa kullanıcı arayüzü öğesi etkin olmadığını hissedebilir.

Sürüklenebilir başparmaklar

Küçük resim öğesi, konumunu .gui-switch > input kapsamlı var(--thumb-position) öğesinden alır. JavaScript, başparmak konumunu dinamik olarak güncellemek için girişte bir satır içi stil değeri sağlayarak işaretçi hareketini izliyormuş gibi görünmesini sağlayabilir. İşaretçi serbest bırakıldığında satır içi stilleri kaldırın ve özel --thumb-position özelliğini kullanarak sürüklemenin kapalı mı yoksa açık mı olduğunu belirleyin. Bu, çözümün omurgasıdır; CSS özel özelliklerini değiştirmek için işaretçi konumlarını koşullu olarak izleyen işaretçi etkinlikleri.

Bu komut dosyası gösterilmeden önce bileşen zaten% 100 işlevsel olduğundan, mevcut davranışı sürdürmek için çok fazla çalışma yapılması (girişi değiştirmek için bir etiketi tıklama gibi) yapılması gerekir. JavaScript'imiz, mevcut özelliklerin pahasına yeni özellikler eklememelidir.

touch-action

Sürükleme, touch-action avantajları için mükemmel bir aday olan özel bir harekettir. Bu geçişte, yatay bir hareket komut dosyamız veya dikey geçiş varyantı için yakalanan dikey bir hareket tarafından gerçekleştirilmelidir. touch-action ile tarayıcıya bu öğede hangi hareketlerin ele alınacağını söyleyebiliriz. Böylece komut dosyası, hareketi herhangi bir rekabet olmadan işleyebilir.

Aşağıdaki CSS, tarayıcıya bir işaretçi hareketi bu geçiş parçasından başladığında dikey hareketleri işlemesini, yatay hareketlerle hiçbir şey yapmamasını söyler:

.gui-switch > input {
  touch-action: pan-y;
}

İstenen sonuç, sayfayı kaydırmayan veya kaydırmayan bir yatay harekettir. İşaretçi, girişten başlayarak dikey olarak kaydırabilir ve sayfayı kaydırabilir ancak yatay olanlar özel olarak işlenir.

Piksel değeri stili yardımcı programları

Kurulum sırasında ve sürükleme sırasında, öğelerden çeşitli hesaplanmış sayı değerlerinin alınması gerekir. Aşağıdaki JavaScript işlevleri, bir CSS özelliğine göre hesaplanmış piksel değerleri döndürür. Bu parametre, getStyle(checkbox, 'padding-left') gibi kurulum komut dosyasında kullanılır.

​​const getStyle = (element, prop) => {
  return parseInt(window.getComputedStyle(element).getPropertyValue(prop));
}

const getPseudoStyle = (element, prop) => {
  return parseInt(window.getComputedStyle(element, ':before').getPropertyValue(prop));
}

export {
  getStyle,
  getPseudoStyle,
}

window.getComputedStyle() işlevinin ikinci bir bağımsız değişkeni (hedef sözde öğe) kabul ettiğine dikkat edin. JavaScript'in, sözde öğeler de dahil olmak üzere öğelerden bu kadar çok değeri okuyabilmesi çok kullanışlı.

dragging

Bu, sürükleme mantığı için temel bir andır ve işlev etkinliği işleyicisinden dikkat edilmesi gereken birkaç nokta vardır:

const dragging = event => {
  if (!state.activethumb) return

  let {thumbsize, bounds, padding} = switches.get(state.activethumb.parentElement)
  let directionality = getStyle(state.activethumb, '--isLTR')

  let track = (directionality === -1)
    ? (state.activethumb.clientWidth * -1) + thumbsize + padding
    : 0

  let pos = Math.round(event.offsetX - thumbsize / 2)

  if (pos < bounds.lower) pos = 0
  if (pos > bounds.upper) pos = bounds.upper

  state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)
}

Komut dosyası kahramanı state.activethumb'tir. Bu komut dosyasının bir işaretçiyle birlikte yerleştirdiği küçük dairedir. switches nesnesi, anahtarların .gui-switch olduğu ve değerlerin komut dosyasını verimli tutan önbelleğe alınmış sınırlar ve boyutlar olduğu bir Map()'tır. Sağdan sola akış, CSS'nin kullandığı özel mülk --isLTR ile yönetilir ve mantığı tersine çevirmek ve RTL'yi desteklemeye devam etmek için kullanılabilir. Başparmak konumlandırması için yararlı bir delta değeri içerdiğinden event.offsetX de değerlidir.

state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)

Bu son CSS satırı, küçük resim öğesi tarafından kullanılan özel özelliği ayarlar. Bu değer atama işlemi normalde zaman içinde geçiş yapar ancak önceki bir işaretçi etkinliği --thumb-transition-duration değerini geçici olarak 0s olarak ayarlayarak yavaş bir etkileşimi ortadan kaldırır.

dragEnd

Kullanıcının anahtarı çok uzak bir yere sürükleyip bırakmasına izin vermek için küresel bir pencere etkinliği kaydedilmesi gerekir:

window.addEventListener('pointerup', event => {
  if (!state.activethumb) return

  dragEnd(event)
})

Kullanıcının serbestçe sürükleme özgürlüğüne sahip olması ve arayüzün bunu hesaba katacak kadar akıllı olması çok önemli. Bu geçişle ilgili sorunu çözmek çok fazla zaman almadı ancak geliştirme sürecinde dikkatli bir şekilde ele alınması gerekiyordu.

const dragEnd = event => {
  if (!state.activethumb) return

  state.activethumb.checked = determineChecked()

  if (state.activethumb.indeterminate)
    state.activethumb.indeterminate = false

  state.activethumb.style.removeProperty('--thumb-transition-duration')
  state.activethumb.style.removeProperty('--thumb-position')
  state.activethumb.removeEventListener('pointermove', dragging)
  state.activethumb = null

  padRelease()
}

Öğeyle etkileşim tamamlandı. Giriş kontrollü mülkünü ayarlama ve tüm hareket etkinliklerini kaldırma zamanı. Onay kutusu state.activethumb.checked = determineChecked() ile değiştirilir.

determineChecked()

dragEnd tarafından çağrılan bu işlev, baş akımının kanalın sınırları içinde nerede olduğunu belirler ve yol boyunca eşit veya yarısına eşit olduğunda true değerini döndürür:

const determineChecked = () => {
  let {bounds} = switches.get(state.activethumb.parentElement)

  let curpos =
    Math.abs(
      parseInt(
        state.activethumb.style.getPropertyValue('--thumb-position')))

  if (!curpos) {
    curpos = state.activethumb.checked
      ? bounds.lower
      : bounds.upper
  }

  return curpos >= bounds.middle
}

Ek düşünceler

Seçilen ilk HTML yapısı nedeniyle sürükleme hareketi biraz kod borcuna neden oldu. Bu yapının en önemli özelliği, girişin bir etikete sarmalanmasıydı. Ebeveyn öğe olan etiket, girişten sonra tıklama etkileşimlerini alır. dragEnd etkinliğinin sonunda, padRelease() işlevinin garip bir şekilde seslendirildiğini fark etmiş olabilirsiniz.

const padRelease = () => {
  state.recentlyDragged = true

  setTimeout(_ => {
    state.recentlyDragged = false
  }, 300)
}

Bu, kullanıcının gerçekleştirdiği etkileşimin işaretini kaldıracağı veya işaretleyeceği için etiketin bu sonraki tıklamayı aldığını hesaba katmaktır.

Bunu tekrar yapacak olsaydım, etiket tıklamalarını kendi başına yöneten ve yerleşik davranışla çakışmayan bir öğe oluşturmak için kullanıcı deneyimi yükseltme sırasında DOM'u JavaScript ile ayarlama seçeneğini değerlendirebilirdim.

Bu tür JavaScript'i yazmak en sevmediğim şeylerden biridir. Koşullu etkinlik kabartmayı yönetmek istemiyorum:

const preventBubbles = event => {
  if (state.recentlyDragged)
    event.preventDefault() && event.stopPropagation()
}

Sonuç

Bu küçük anahtar bileşeni, bugüne kadarki tüm GUI yarışmalarında en çok çalışma gerektiren bileşen oldu. Bunu nasıl yaptığımı öğrendiğinize göre, siz ne yapardınız? 🙂

Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim. Bir demo oluşturun, bağlantılarını bana tweetleyin. Ardından, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.

Topluluk remiksleri

Kaynaklar

.gui-switch Kaynak kodunu GitHub'da bulun.