Switch-Komponente erstellen

Ein grundlegender Überblick über die Erstellung einer responsiven und barrierefreien Schalterkomponente.

In diesem Beitrag möchte ich auf meine Gedanken zum Erstellen von Switch-Komponenten eingehen. Demo ansehen.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> Demo

Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:

Übersicht

Ein Schalter funktioniert ähnlich wie ein Kästchen. stellt aber explizit boolesche Ein- und Ausschaltstatus dar.

In dieser Demo wird <input type="checkbox" role="switch"> für den Großteil der Diese Funktion hat den Vorteil, dass CSS oder JavaScript voll funktionsfähig und barrierefrei zugänglich ist. Durch das Laden von CSS wird die linksläufige Schreibrichtung unterstützt. Sprachen, Vertikalität, Animation und mehr. Wenn JavaScript geladen wird, ziehbar und greifbar.

Benutzerdefinierte Eigenschaften

Die folgenden Variablen repräsentieren die verschiedenen Teile des Switches und ihre Optionen. Als Klasse der obersten Ebene enthält .gui-switch benutzerdefinierte Eigenschaften, die verwendet werden. in allen untergeordneten Komponenten und Einstiegspunkte für zentralisierte Personalisierung.

Verfolgen

Die Länge (--track-size), der Abstand und zwei Farben:

.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%);
  }
}

Thumbnails

Größe, Hintergrundfarbe und Hervorhebungsfarben für Interaktionen:

.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%);
  }
}

Reduzierte Bewegungsfreiheit

Um einen eindeutigen Alias hinzuzufügen und Wiederholungen zu reduzieren, wurde die Bewegungseinstellung für Nutzer reduziert. können Sie mit der Funktion PostCSS Plug-in auf Basis dieses Entwurfs Spezifikation in Medienabfragen 5:

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

Markup

Ich habe mich entschieden, mein <input type="checkbox" role="switch">-Element mit einem <label>, die Beziehung wird gebündelt, um eine Verknüpfung von Kästchen und Labels zu vermeiden und den Nutzenden die Möglichkeit geben, mit dem Label zu interagieren, um den Eingang ein-/auszuschalten.

A
Natürliches, unformatiertes Label und Kästchen.

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

In <input type="checkbox"> ist bereits Folgendes vorinstalliert: API und state. Die der Browser verwaltet checked und Eingaben Veranstaltungen wie oninput und onchanged.

Layouts

Flexbox grid und custom Properties die Stile dieser Komponente beibehalten. Sie zentralisieren Werte, geben Namen auf ansonsten mehrdeutige Berechnungen oder Flächen API für einfache Komponentenanpassungen

.gui-switch

Das Layout der obersten Ebene für den Schalter ist Flexbox. Die Klasse .gui-switch enthält Die privaten und öffentlichen benutzerdefinierten Eigenschaften, mit denen die untergeordneten Elemente ihre Layouts.

Flexbox-Entwicklertools überlagern ein horizontales Label und einen Schalter mit dem Layout
die Verteilung des Raums.

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

Das Erweitern und Ändern des Flexbox-Layouts entspricht dem Ändern eines beliebigen Flexbox-Layouts. Zum Beispiel, um Labels über oder unter einem Schalter zu platzieren oder um den flex-direction:

Flexbox-Entwicklertools überlagern ein vertikales Label und einen Schalter.

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

Verfolgen

Die Kästcheneingabe wird wie eine Schaltspur dargestellt, indem die normale appearance: checkbox und stellt stattdessen seine eigene Größe bereit:

Grid-Entwicklertools überlagern den Switch-Track und zeigen den benannten Raster-Track
Gebiete mit dem Namen &quot;track&quot;.

.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;
}

Der Track erstellt außerdem einen Raster-Trackbereich mit einer einzelnen Zelle, den Sie mit dem Daumen Anspruch erheben.

Thumbnails

Mit dem Stil appearance: none wird auch das visuelle Häkchen des Browser. Diese Komponente verwendet ein Pseudoelement und :checked pseudo-class bei der Eingabe können Sie diesen visuellen Indikator ersetzen.

Der „thumb“ ist ein untergeordnetes Pseudoelement, das mit input[type="checkbox"] verknüpft ist. über dem Track statt darunter stapeln, indem Sie den Rasterbereich beanspruchen track:

Entwicklertools, die den Pseudoelement-Daumen in einem CSS-Raster zeigen

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

Stile

Benutzerdefinierte Eigenschaften ermöglichen eine vielseitige Schalterkomponente, die sich an Farben anpasst linksläufige Sprachen und Bewegungseinstellungen.

Eine Gegenüberstellung des hellen und des dunklen Designs für den Schalter
Bundesländer.

Berührungs-Interaktionsstile

Auf Mobilgeräten fügen Browser Tipphervorhebungen und Textauswahlfunktionen zu Labels und Eingaben. Dies beeinträchtigte den Stil und das visuelle Interaktionsfeedback, dieser Schalter erforderlich war. Mit ein paar CSS-Zeilen kann ich diese Effekte entfernen Mein eigener cursor: pointer-Stil:

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

Es ist nicht immer ratsam, diese Stile zu entfernen, da sie visuell wertvoll sein können Interaktions-Feedback. Geben Sie unbedingt benutzerdefinierte Alternativen an, wenn Sie diese entfernen.

Verfolgen

Bei den Stilen dieses Elements geht es hauptsächlich um seine Form und Farbe, auf die es zugreift vom übergeordneten Element .gui-switch über die Cascade.

Die Switch-Varianten sind mit benutzerdefinierten Track-Größen und -Farben verfügbar.

.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);
}

Es gibt vier Anpassungsoptionen benutzerdefinierten Eigenschaften. border: none wurde hinzugefügt, da appearance: none dies nicht entfernen Sie die Rahmen in allen Browsern aus dem Kontrollkästchen.

Thumbnails

Das „thumb“-Element befindet sich bereits auf der rechten Seite track, benötigt jedoch einen Kreisstil:

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

Die dargestellten Entwicklertools sind das Pseudoelement eines Kreises, der markiert ist.

Interaktion

Benutzerdefinierte Eigenschaften verwenden, um Interaktionen vorzubereiten, bei denen der Mauszeiger darauf bewegt wird und Änderungen der Daumenposition. Die Präferenz des Nutzers ist ebenfalls ausgewählt, bevor Sie den oder den Mauszeiger darauf bewegen.

.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;
  }}
}

Daumenposition

Benutzerdefinierte Eigenschaften bieten eine einzige Quelle für die Positionierung des „Mag ich“-Effekts in den Titel. Wir bieten Ihnen die Track- und Thumbnail-Größen, die wir in um den Daumen mit Abstand und zwischen den Tracks zu verschieben: 0% und 100%.

Das Element input besitzt die Positionsvariable --thumb-position und das „thumb“-Element wird es vom Pseudoelement als translateX-Position verwendet:

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

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

Wir können --thumb-position jetzt frei von CSS und den Pseudoklassen ändern. für Kästchenelemente. Da wir zuvor für dieses Element transition: transform var(--thumb-transition-duration) ease bedingt festgelegt haben, ändern sich diese Änderungen kann bei Änderung animiert werden:

/* 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)
  );
}

Ich fand, dass diese entkoppelte Orchestrierung gut funktioniert hat. Das „thumb“-Element ist betrifft nur ein Design, eine translateX-Position. Die Eingabe kann alle Komplexität und Berechnungen.

Branche

Die Unterstützung wurde mit der Modifikatorklasse -vertical durchgeführt, die eine Rotation mit CSS-Transformationen werden in das input-Element umgewandelt.

Ein 3D-Drehelement ändert jedoch nicht die Gesamthöhe der Komponente, was das Block-Layout durcheinanderbringen kann. Berücksichtigen Sie dies mithilfe von --track-size und --track-padding Variablen. Berechnen Sie den minimalen Speicherplatz, der für eine vertikale Schaltfläche, um wie erwartet im Layout zu verlaufen:

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

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

Rechts-nach-links (RTL)

Ein Freund von CSS, Elad Schecter, und ich haben einen Prototyp ein Seitenmenü mit CSS-Transformationen, die von rechts nach links bewegt wurden, Sprachen durch Umdrehen eines einzelnen . Wir haben dies getan, weil es in CSS keine logischen Eigenschaftstransformationen gibt. und die werden es vielleicht nie geben. Elad hatte die Idee, einen Wert für eine benutzerdefinierte Eigenschaft zu verwenden. Prozentsätze umkehren, um die Verwaltung von benutzerdefinierten Logik für logische Transformationen. Ich habe diese Technik auch bei diesem Schalter verwendet. fanden, dass es gut funktioniert hat:

.gui-switch {
  --isLTR: 1;

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

Eine benutzerdefinierte Eigenschaft namens --isLTR hat anfangs den Wert 1. Es ist also true, da das Layout standardmäßig von links nach rechts ist. Dann können Sie mit dem CSS-Code Pseudoklasse :dir() wird der Wert auf -1 gesetzt, wenn sich die Komponente in einem linksläufigen Layout befindet.

Setzen Sie --isLTR in Aktion um, indem Sie es innerhalb einer calc() innerhalb einer Transformation verwenden:

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

Durch die Drehung des vertikalen Schalters wird die Position der gegenüberliegenden Seite berücksichtigt. die für das Rechts-nach-links-Layout erforderlich sind.

Das translateX-Element im Pseudoelement für den Daumen muss ebenfalls so geändert werden, dass es Anforderung der Gegenseite berücksichtigen:

.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)
  );
}

Dieser Ansatz eignet sich nicht, um alle Anforderungen an ein Konzept wie logisches CSS zu erfüllen. bietet es einige DRY-Prinzipien für viele Anwendungsfälle.

Bundesstaaten

Ohne die integrierte input[type="checkbox"]-Lösung die möglichen Statusangaben verarbeiten: :checked, :disabled, :indeterminate und :hover. :focus wurde absichtlich in Angriff genommen, mit einem Anpassungen nur an ihrem Offset; sah der Fokusring in Firefox und Safari:

Screenshot eines Fokusrings mit Fokus auf einem Schalter in Firefox und Safari.

Geprüft

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

Dieser Status stellt den Status on dar. In diesem Status wird die Eingabe der Hintergrund auf die aktive Farbe gesetzt ist und die Daumenposition auf end".

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

Deaktiviert

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

Eine :disabled-Schaltfläche sieht nicht nur optisch anders aus, sondern sollte auch -Element unveränderlich.Die Unveränderlichkeit der Interaktion ist vom Browser kostenlos, aber die Eigenschaft Für visuelle Zustände sind aufgrund der Verwendung von appearance: none Stile erforderlich.

.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%);
    }}
  }
}

Der dunkle Schalter ist deaktiviert, aktiviert und deaktiviert
Bundesländer.

Dieser Zustand ist schwierig, da dunkle und helle Designs erforderlich sind, bei denen sowohl deaktivierte als auch geprüften Status. Ich habe für diese Staaten stilistisch minimale Stile ausgewählt, den Verwaltungsaufwand der Stilkombinationen.

Unklar

Ein häufig vergessener Status ist :indeterminate, wobei ein Kästchen keine von beiden aktiviert oder deaktiviert ist. Das macht Spaß, ist einladend und unscheinbar. Eine gute zur Erinnerung, dass boolesche Zustände zwischen den Zuständen versteckt sein können.

Es ist schwierig, ein Kästchen auf „Unbestimmt“ festzulegen. Nur JavaScript kann es setzen:

<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>

Der unbestimmte Zustand, bei dem der Track-Daumen im Feld
in der Mitte, um auf &quot;unentschlossen&quot; hinzuweisen.

Da der Bundesstaat für mich unaufdringlich und einladend ist, fühlte es sich an, Schalter-Daumenposition in der Mitte:

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

Mauszeiger hierher bewegen

Interaktionen über den Mauszeiger sollten die verbundene Benutzeroberfläche visuell unterstützen Richtung der interaktiven Benutzeroberfläche. Dieser Schalter hebt den Daumen mit ein halbtransparenter Ring, wenn der Mauszeiger auf das Label oder die Eingabe bewegt wird. Diese Mausbewegung gibt die Animation die Richtung des interaktiven Thumbnail-Elements vor.

Das „Highlight“ wird mit box-shadow vorgenommen. Wenn der Mauszeiger auf eine nicht deaktivierte Eingabe bewegt wird, wird die Größe von --highlight-size erhöht. Wenn der Nutzer mit Bewegung einverstanden ist, wechseln wir den box-shadow und sehen, wie er größer wird. Ist Bewegung nicht akzeptabel, wird die Markierung sofort angezeigt:

.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

Ich finde es unheimlich, wenn eine Switch-Oberfläche eine physische insbesondere diese mit einem Kreis innerhalb der Spur. iOS hat das richtig gemacht können Sie sie von einer Seite zur anderen ziehen. die Möglichkeit haben. Umgekehrt kann sich ein UI-Element als inaktiv anfühlen, wenn eine Ziehgeste und es passiert nichts.

Ziehbare Daumen

Das Pseudoelement für den Daumen erhält seine Position vom .gui-switch > input. mit Geltungsbereich var(--thumb-position), kann JavaScript einen Inline-Style-Wert für Die Eingabe, um die Daumenposition dynamisch zu aktualisieren, sodass sie dem Anschein nach zu folgen die Zeiger-Geste verwenden. Wenn der Zeiger losgelassen wird, entfernen Sie die Inline-Stile und Ermitteln, ob der Ziehpunkt näher an „Aus“ oder „An“ lag, indem die benutzerdefinierte Eigenschaft verwendet wird --thumb-position Dies ist das Rückgrat der Lösung: Zeigerereignisse Zeigerpositionen bedingt erfassen, um benutzerdefinierte CSS-Eigenschaften zu ändern.

Da die Komponente bereits zu 100% funktionsfähig war, bevor dieses Skript angezeigt wird, ist es ziemlich aufwendig, das bestehende Verhalten aufrechtzuerhalten, Klicken Sie auf ein Label, um die Eingabe zu wechseln. Unser JavaScript sollte keine Funktionen unter und die Kosten vorhandener Funktionen.

touch-action

Das Ziehen ist eine benutzerdefinierte Geste und eignet sich daher gut für Vorteile von touch-action. Bei diesem Schalter sollte eine horizontale Geste vom Script verarbeitet werden, oder eine vertikale Geste, die für den vertikalen Wechsel erfasst wurde Variante. Mit touch-action können wir dem Browser mitteilen, welche Gesten auf damit das Skript eine Geste ohne Konkurrenz verarbeiten kann.

Mit dem folgenden CSS-Code wird der Browser angewiesen, in diesem Schalter-Track, vertikale Gesten verarbeiten, nichts mit horizontalen Gesten machen eins:

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

Das gewünschte Ergebnis ist eine horizontale Bewegung, bei der die Seite. Ein Zeiger kann vertikal scrollen, beginnend innerhalb der Eingabe und scrollt Seiten, aber horizontale werden benutzerdefiniert bearbeitet.

Dienstprogramme für den Stil von Pixel-Werten

Bei der Einrichtung und während des Ziehens müssen verschiedene berechnete Zahlenwerte erfasst werden. aus Elementen zu extrahieren. Die folgenden JavaScript-Funktionen geben berechnete Pixelwerte zurück CSS-Eigenschaft angegeben werden. Er wird im Einrichtungsskript wie folgt verwendet: getStyle(checkbox, 'padding-left')

​​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,
}

Beachten Sie, wie window.getComputedStyle() ein zweites Argument annimmt, ein Pseudoelement. Ziemlich praktisch, dass JavaScript so viele Werte aus Elementen lesen kann, auch aus Pseudoelementen.

dragging

Dies ist ein zentraler Moment der Drag-Logik und es gibt einige Dinge, aus dem Event-Handler der Funktion:

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`)
}

Der Held des Skripts ist state.activethumb, der kleine Kreis, in dem das Skript zu sehen ist mit einem Zeiger positioniert werden. Das switches-Objekt ist ein Map(), bei dem der Schlüssel sind .gui-switch-Schlüssel und die Werte sind zwischengespeicherte Grenzen und Größen, die das Skript effizient zu gestalten. Linksläufig wird die gleiche benutzerdefinierte Eigenschaft verwendet. dass der CSS-Code --isLTR ist und damit die Logik umkehren und fortfahren mit RTL. Auch event.offsetX ist hilfreich, da es ein Delta enthält. -Wert, der für die Positionierung des Daumens nützlich ist.

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

Mit dieser letzten CSS-Zeile wird die vom thumb-Element verwendete benutzerdefinierte Eigenschaft festgelegt. Dieses würde die Wertezuweisung mit der Zeit übergangen werden, aber ein vorheriger Zeiger Für dieses Ereignis wurde „--thumb-transition-duration“ vorübergehend auf 0s gesetzt. Dabei wird Folgendes entfernt: nur sehr schleppend gewesen wäre.

dragEnd

Damit der Nutzer weit aus dem Schalter heraus ziehen und loslassen kann, Erforderliches globales Fensterereignis registriert:

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

  dragEnd(event)
})

Ich denke, es ist sehr wichtig, dass Nutzende die Freiheit haben, Benutzeroberfläche so intelligent sein, dass sie das berücksichtigt. Es hat nicht viel gedauert, um damit umzugehen diese Umstellung erforderte aber sorgfältige Überlegungen. .

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()
}

Interaktion mit dem Element ist abgeschlossen, Zeit zum Festlegen der Eingabe ist aktiviert und entfernen Sie alle Bewegungsereignisse. Das Kästchen wird geändert mit state.activethumb.checked = determineChecked()

determineChecked()

Diese von dragEnd aufgerufene Funktion bestimmt, wo der Daumenstrom innerhalb der Grenzen des Tracks liegt und gibt "true" zurück, wenn der Wert gleich oder darüber ist auf der Hälfte der Strecke:

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
}

Zusätzliche Gedanken

Durch die Drag-Geste entstanden aufgrund der anfänglichen HTML-Struktur einige Code-Altlasten. vor allem das Einbinden der Eingabe in ein Label. Das Label als übergeordnetes Element -Elements nach der Eingabe Klickinteraktionen erhalten. Am Ende des dragEnd-Ereignis, hast du vielleicht schon bemerkt, dass padRelease() seltsam klingt .

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

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

Damit wird das Label berücksichtigt, das diesen späteren Klick erhält, da es das Häkchen die Interaktion eines Nutzers.

In diesem Fall könnte ich das DOM mit JavaScript anpassen. während des UX-Upgrades, z. B. um ein Element zu erstellen, das Labelklicks selbst verarbeitet. und kämpft nicht mit dem integrierten Verhalten.

Diese Art von JavaScript schreibe ich am liebsten, bedingtes Ereignis-Bubbling:

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

Fazit

Diese teeny-Switch-Komponente war die meiste Arbeit in allen GUI-Challenges. soweit! Jetzt, wo du weißt, wie ich es gemacht habe, wie würdest du... ‽ 🙂

Lassen Sie uns unsere Herangehensweisen diversifizieren und alle Möglichkeiten kennenlernen, wie wir das Web entwickeln können. Erstelle eine Demo, twittere mir Links und ich füge sie hinzu im Abschnitt „Community-Remixe“ weiter unten.

Community-Remixe

Ressourcen

Den Quellcode von .gui-switch finden Sie auf GitHub