Wie man formatierte Ausgaben in Teile für das Styling aufteilt

Verwenden Sie formatToParts(), um auf einzelne Komponenten der formatierten Ausgabe für benutzerdefiniertes Styling zuzugreifen

Einführung

Die format()-Methode bei JavaScript-Formatierern gibt vollständige Zeichenketten wie "$1,234.56" oder "January 15, 2025" zurück. Dies funktioniert gut für einfache Anzeigen, aber Sie können einzelne Teile nicht unterschiedlich gestalten. Sie können das Währungssymbol nicht fett formatieren, den Monatsnamen nicht anders einfärben oder benutzerdefinierte Markierungen auf bestimmte Komponenten anwenden.

JavaScript bietet die formatToParts()-Methode, um dieses Problem zu lösen. Anstatt eine einzelne Zeichenkette zurückzugeben, gibt sie ein Array von Objekten zurück, wobei jedes Objekt einen Teil der formatierten Ausgabe darstellt. Jeder Teil hat einen Typ wie currency, month oder element und einen Wert, der die eigentliche Zeichenkette enthält. Sie können diese Teile dann verarbeiten, um benutzerdefinierte Formatierungen anzuwenden, komplexe Layouts zu erstellen oder formatierte Inhalte in umfangreiche Benutzeroberflächen zu integrieren.

Die formatToParts()-Methode ist bei mehreren Intl-Formatierern verfügbar, einschließlich NumberFormat, DateTimeFormat, ListFormat, RelativeTimeFormat und DurationFormat. Dies macht sie zu einem konsistenten Muster für alle Internationalisierungsformatierungen in JavaScript.

Warum formatierte Zeichenketten nicht einfach gestaltet werden können

Wenn Sie eine formatierte Zeichenkette wie "$1,234.56" erhalten, können Sie nicht einfach erkennen, wo das Währungssymbol endet und die Zahl beginnt. Verschiedene Gebietsschemas platzieren Symbole an unterschiedlichen Positionen. Einige Gebietsschemas verwenden unterschiedliche Trennzeichen. Das zuverlässige Parsen dieser Zeichenketten erfordert komplexe Logik, die die bereits in der Intl-API implementierten Formatierungsregeln dupliziert.

Stellen Sie sich ein Dashboard vor, das Geldbeträge mit dem Währungssymbol in einer anderen Farbe anzeigt. Mit format() müssten Sie:

  1. Erkennen, welche Zeichen das Währungssymbol sind
  2. Leerzeichen zwischen dem Symbol und der Zahl berücksichtigen
  3. Unterschiedliche Symbolpositionen in verschiedenen Gebietsschemas behandeln
  4. Die Zeichenkette sorgfältig parsen, um die Zahl nicht zu beschädigen

Dieser Ansatz ist fehleranfällig und störungsanfällig. Jede Änderung an den Formatierungsregeln des Gebietsschemas bricht Ihre Parsing-Logik.

Das gleiche Problem existiert für Datumsangaben, Listen und andere formatierte Ausgaben. Sie können formatierte Zeichenketten nicht zuverlässig parsen, um Komponenten zu identifizieren, ohne die gebietsschemaspezifischen Formatierungsregeln neu zu implementieren.

Die formatToParts()-Methode beseitigt dieses Problem, indem sie die Komponenten separat bereitstellt. Sie erhalten strukturierte Daten, die Ihnen genau mitteilen, welcher Teil welcher ist, unabhängig vom Gebietsschema.

Wie formatToParts funktioniert

Die Methode formatToParts() funktioniert identisch zu format(), mit Ausnahme des Rückgabewerts. Sie erstellen einen Formatierer mit denselben Optionen und rufen dann formatToParts() anstelle von format() auf.

Die Methode gibt ein Array von Objekten zurück. Jedes Objekt enthält zwei Eigenschaften:

  • type: Identifiziert, was der Teil darstellt, wie currency, month oder literal
  • value: Enthält die tatsächliche Zeichenfolge für diesen Teil

Die Teile erscheinen in derselben Reihenfolge wie in der formatierten Ausgabe. Sie können dies überprüfen, indem Sie alle Werte zusammenfügen, was genau die gleiche Ausgabe erzeugt wie der Aufruf von format().

Dieses Muster ist bei allen Formatierern konsistent, die formatToParts() unterstützen. Die spezifischen Teiltypen variieren je nach Formatierer, aber die Struktur ist immer gleich.

Formatierte Zahlen in Teile aufteilen

Der NumberFormat-Formatierer bietet formatToParts() zum Aufschlüsseln formatierter Zahlen. Dies funktioniert für einfache Zahlen, Währungen, Prozentsätze und andere numerische Stile.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = formatter.formatToParts(1234.56);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "currency", value: "$" },
  { type: "integer", value: "1" },
  { type: "group", value: "," },
  { type: "integer", value: "234" },
  { type: "decimal", value: "." },
  { type: "fraction", value: "56" }
]

Jedes Objekt identifiziert, was der Teil darstellt, und liefert seinen Wert. Der Typ currency repräsentiert das Währungssymbol. Der Typ integer repräsentiert ganze Ziffern. Der Typ group repräsentiert das Tausendertrennzeichen. Der Typ decimal repräsentiert den Dezimalpunkt. Der Typ fraction repräsentiert Ziffern nach dem Dezimalpunkt.

Sie können überprüfen, ob die Teile mit der formatierten Ausgabe übereinstimmen:

const formatted = parts.map(part => part.value).join("");
console.log(formatted);
// Ausgabe: "$1,234.56"

Die verketteten Teile erzeugen genau die gleiche Ausgabe wie der Aufruf von format().

Styling von Währungssymbolen in formatierten Zahlen

Der primäre Anwendungsfall für formatToParts() ist die Anwendung verschiedener Stile auf unterschiedliche Komponenten. Sie können das Parts-Array verarbeiten, um bestimmte Typen in HTML-Elemente einzuschließen.

Das Währungssymbol fett formatieren:

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = formatter.formatToParts(1234.56);
const html = parts
  .map(part => {
    if (part.type === "currency") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>$</strong>1,234.56"

Dieser Ansatz funktioniert für jede Markup-Sprache. Sie können HTML, JSX oder jedes andere Format generieren, indem Sie das Parts-Array verarbeiten.

Dezimalstellen anders formatieren:

const formatter = new Intl.NumberFormat("en-US", {
  minimumFractionDigits: 2
});

const parts = formatter.formatToParts(1234.5);
const html = parts
  .map(part => {
    if (part.type === "decimal" || part.type === "fraction") {
      return `<span class="text-gray-500">${part.value}</span>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "1,234<span class="text-gray-500">.50</span>"

Dieses Muster ist üblich bei Preisanzeigen, bei denen der Dezimalteil kleiner oder heller erscheint.

Aufteilen formatierter Datumsangaben in Einzelteile

Der DateTimeFormat-Formatierer bietet formatToParts() zum Aufschlüsseln formatierter Datums- und Zeitangaben.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "month", value: "January" },
  { type: "literal", value: " " },
  { type: "day", value: "15" },
  { type: "literal", value: ", " },
  { type: "year", value: "2025" }
]

Der Typ month repräsentiert den Monatsnamen oder die Monatszahl. Der Typ day repräsentiert den Tag des Monats. Der Typ year repräsentiert das Jahr. Der Typ literal repräsentiert Leerzeichen, Interpunktion oder anderen Text, der vom Formatierer eingefügt wird.

Styling von Monatsnamen in formatierten Datumsangaben

Sie können benutzerdefinierte Formatierungen auf Datumskomponenten anwenden, indem Sie das gleiche Muster wie bei Zahlen verwenden.

Den Monatsnamen fett formatieren:

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
  .map(part => {
    if (part.type === "month") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>January</strong> 15, 2025"

Formatierung mehrerer Datumskomponenten:

const formatter = new Intl.DateTimeFormat("en-US", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);

const html = parts
  .map(part => {
    switch (part.type) {
      case "weekday":
        return `<span class="font-bold">${part.value}</span>`;
      case "month":
        return `<span class="text-blue-600">${part.value}</span>`;
      case "year":
        return `<span class="text-gray-500">${part.value}</span>`;
      default:
        return part.value;
    }
  })
  .join("");

console.log(html);
// Output: "<span class="font-bold">Wednesday</span>, <span class="text-blue-600">January</span> 15, <span class="text-gray-500">2025</span>"

Diese granulare Kontrolle ermöglicht präzise Formatierung für jede Komponente.

Aufteilen formatierter Listen in Einzelteile

Der ListFormat-Formatierer bietet formatToParts() zur Aufschlüsselung formatierter Listen.

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "element", value: "apples" },
  { type: "literal", value: ", " },
  { type: "element", value: "oranges" },
  { type: "literal", value: ", and " },
  { type: "element", value: "bananas" }
]

Der Typ element repräsentiert jedes Element in der Liste. Der Typ literal repräsentiert Trennzeichen und Konjunktionen, die vom Formatierer hinzugefügt werden.

Individuelle Gestaltung von Listenelementen

Sie können benutzerdefinierte Formatierungen auf Listenelemente mit demselben Muster anwenden.

Listenelemente fett formatieren:

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
const html = parts
  .map(part => {
    if (part.type === "element") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>apples</strong>, <strong>oranges</strong>, and <strong>bananas</strong>"

Bestimmte Listenelemente formatieren:

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);

let itemIndex = 0;
const html = parts
  .map(part => {
    if (part.type === "element") {
      const currentIndex = itemIndex++;
      if (currentIndex === 0) {
        return `<span class="text-green-600">${part.value}</span>`;
      }
      return part.value;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<span class="text-green-600">apples</span>, oranges, and bananas"

Dieser Ansatz ermöglicht es Ihnen, bestimmte Elemente hervorzuheben und gleichzeitig die korrekte sprachspezifische Formatierung beizubehalten.

Aufteilen formatierter relativer Zeitangaben in Teile

Der RelativeTimeFormat-Formatierer bietet formatToParts() zur Aufschlüsselung relativer Zeitausdrücke.

const formatter = new Intl.RelativeTimeFormat("en-US", {
  numeric: "auto"
});

const parts = formatter.formatToParts(-1, "day");
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "literal", value: "yesterday" }
]

Für numerische relative Zeitangaben:

const formatter = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always"
});

const parts = formatter.formatToParts(-3, "day");
console.log(parts);
// [
//   { type: "integer", value: "3" },
//   { type: "literal", value: " days ago" }
// ]

Der Typ integer repräsentiert den numerischen Wert. Der Typ literal repräsentiert die relative Zeiteinheit und Richtung.

Formatierte Zeitdauern in Teile aufteilen

Der DurationFormat-Formatierer bietet formatToParts() zum Aufschlüsseln formatierter Zeitdauern.

const formatter = new Intl.DurationFormat("en-US", {
  style: "long"
});

const parts = formatter.formatToParts({
  hours: 2,
  minutes: 30,
  seconds: 15
});
console.log(parts);

Dies gibt ein Array von Objekten aus, ähnlich wie:

[
  { type: "integer", value: "2" },
  { type: "literal", value: " hours, " },
  { type: "integer", value: "30" },
  { type: "literal", value: " minutes, " },
  { type: "integer", value: "15" },
  { type: "literal", value: " seconds" }
]

Der Typ integer repräsentiert numerische Werte. Der Typ literal repräsentiert Einheitennamen und Trennzeichen.

HTML aus formatierten Teilen erstellen

Sie können eine wiederverwendbare Funktion erstellen, die Teile verarbeitet und Stilregeln konsistent anwendet.

function formatWithStyles(parts, styleMap) {
  return parts
    .map(part => {
      const style = styleMap[part.type];
      if (style) {
        return `<span class="${style}">${part.value}</span>`;
      }
      return part.value;
    })
    .join("");
}

const numberFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = numberFormatter.formatToParts(1234.56);
const html = formatWithStyles(parts, {
  currency: "font-bold text-gray-700",
  integer: "text-2xl",
  fraction: "text-sm text-gray-500"
});

console.log(html);
// Output: "<span class="font-bold text-gray-700">$</span><span class="text-2xl">1</span>,<span class="text-2xl">234</span>.<span class="text-sm text-gray-500">56</span>"

Dieses Muster trennt die Stilregeln von der Formatierungslogik, was die Wartung und Wiederverwendung erleichtert.

Verständnis der lokalisierungsspezifischen Teilanordnung

Das Parts-Array behält automatisch die lokalisierungsspezifischen Formatierungsregeln bei. Verschiedene Lokalisierungen platzieren Komponenten in unterschiedlichen Reihenfolgen und verwenden unterschiedliche Formate, aber formatToParts() behandelt diese Unterschiede.

const usdFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

console.log(usdFormatter.formatToParts(1234.56));
// [
//   { type: "currency", value: "$" },
//   { type: "integer", value: "1" },
//   { type: "group", value: "," },
//   { type: "integer", value: "234" },
//   { type: "decimal", value: "." },
//   { type: "fraction", value: "56" }
// ]

const eurFormatter = new Intl.NumberFormat("de-DE", {
  style: "currency",
  currency: "EUR"
});

console.log(eurFormatter.formatToParts(1234.56));
// [
//   { type: "integer", value: "1" },
//   { type: "group", value: "." },
//   { type: "integer", value: "234" },
//   { type: "decimal", value: "," },
//   { type: "fraction", value: "56" },
//   { type: "literal", value: " " },
//   { type: "currency", value: "€" }
// ]

Die deutsche Formatierung platziert die Währung nach der Zahl mit einem Leerzeichen. Das Gruppierungstrennzeichen ist ein Punkt und das Dezimaltrennzeichen ist ein Komma. Ihr Stilcode verarbeitet das Parts-Array auf die gleiche Weise unabhängig von der Lokalisierung, und die Formatierung passt sich automatisch an.

Erstellen von barrierefreien formatierten Anzeigen

Sie können formatToParts() verwenden, um Barrierefreiheitsattribute zu formatierter Ausgabe hinzuzufügen. Dies hilft Screenreadern, Werte korrekt anzukündigen.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

function formatAccessible(number) {
  const parts = formatter.formatToParts(number);
  const formatted = parts.map(part => part.value).join("");

  return `<span aria-label="${number} US dollars">${formatted}</span>`;
}

console.log(formatAccessible(1234.56));
// Output: "<span aria-label="1234.56 US dollars">$1,234.56</span>"

Dies stellt sicher, dass Screenreader sowohl den formatierten Anzeigewert als auch den zugrundeliegenden numerischen Wert mit dem richtigen Kontext ankündigen.

Kombination von formatToParts mit Framework-Komponenten

Moderne Frameworks wie React können formatToParts() nutzen, um Komponenten effizient zu erstellen.

function CurrencyDisplay({ value, locale, currency }) {
  const formatter = new Intl.NumberFormat(locale, {
    style: "currency",
    currency: currency
  });

  const parts = formatter.formatToParts(value);

  return (
    <span className="currency-display">
      {parts.map((part, index) => {
        if (part.type === "currency") {
          return <strong key={index}>{part.value}</strong>;
        }
        if (part.type === "fraction" || part.type === "decimal") {
          return <span key={index} className="text-sm text-gray-500">{part.value}</span>;
        }
        return <span key={index}>{part.value}</span>;
      })}
    </span>
  );
}

Diese Komponente wendet unterschiedliche Formatierungen auf verschiedene Teile an, während die korrekte Formatierung für jede Locale und Währung beibehalten wird.

Wann formatToParts verwenden

Verwenden Sie format(), wenn Sie eine einfache formatierte Zeichenfolge ohne Anpassungen benötigen. Dies ist der häufigste Fall für die meisten Anzeigeszenarios.

Verwenden Sie formatToParts(), wenn Sie:

  • Unterschiedliche Formatierungen auf verschiedene Teile der formatierten Ausgabe anwenden möchten
  • HTML oder JSX mit formatiertem Inhalt erstellen möchten
  • Attribute oder Metadaten zu bestimmten Komponenten hinzufügen möchten
  • Formatierte Ausgabe in komplexe Layouts integrieren möchten
  • Formatierte Ausgabe programmatisch verarbeiten möchten
  • Benutzerdefinierte visuelle Designs erstellen möchten, die eine granulare Kontrolle erfordern

Die Methode formatToParts() hat einen etwas höheren Overhead als format(), da sie ein Array von Objekten anstelle einer einzelnen Zeichenfolge erstellt. Dieser Unterschied ist für typische Anwendungen vernachlässigbar, aber wenn Sie Tausende von Werten pro Sekunde formatieren, bietet format() eine bessere Leistung.

Für die meisten Anwendungen sollten Sie die Wahl basierend auf Ihren Formatierungsanforderungen und nicht auf Leistungsbedenken treffen. Wenn Sie die Ausgabe nicht anpassen müssen, verwenden Sie format(). Wenn Sie benutzerdefinierte Formatierungen oder Markup benötigen, verwenden Sie formatToParts().

Häufige Teiltypen bei verschiedenen Formatierern

Verschiedene Formatierer erzeugen unterschiedliche Teiltypen, aber einige Typen kommen bei mehreren Formatierern vor:

  • literal: Leerzeichen, Interpunktion oder anderer Text, der durch die Formatierung hinzugefügt wird. Erscheint in Datumsangaben, Zahlen, Listen und Zeitdauern.
  • integer: Ganzzahlige Ziffern. Erscheint in Zahlen, relativen Zeitangaben und Zeitdauern.
  • decimal: Dezimaltrennzeichen. Erscheint in Zahlen.
  • fraction: Dezimalstellen. Erscheint in Zahlen.

Formatierer-spezifische Typen umfassen:

  • Zahlen: currency, group, percentSign, minusSign, plusSign, unit, compact, exponentInteger
  • Datumsangaben: weekday, era, year, month, day, hour, minute, second, dayPeriod, timeZoneName
  • Listen: element
  • Relative Zeitangaben: Numerische Werte erscheinen als integer, Text erscheint als literal

Das Verständnis dieser Typen hilft Ihnen, Styling-Code zu schreiben, der die Ausgabe jedes Formatierers korrekt behandelt.