Zum Hauptinhalt springen

Erwähnungen und Tags

RichText unterstützt benutzerdefinierte Trigger-Zeichen, die ein Vorschlag-Dropdown im Dokument öffnen. Wenn der Benutzer ein Element auswählt, fügt RichText ein nicht bearbeitbares Token in das Dokument ein. Typische Anwendungsfälle:

  • @ — eine Person erwähnen
  • # — einen Tag anwenden
  • / — einen Befehl oder eine Vorlage einfügen
  • $ — ein Finanzsymbol oder eine Variable einfügen
  • : — ein Emoji einfügen

Konfigurieren Sie das Verhalten über die Eigenschaft triggers. Jeder Eintrag bindet ein Zeichen an eine Datenquelle.

Trigger konfigurieren

Jeder Trigger ist ein Objekt { trigger, data, showTrigger?, action? } innerhalb des triggers-Arrays. Das Feld data kann drei Formen annehmen:

  • Ein statisches Array — RichText filtert es automatisch nach label (Groß-/Kleinschreibung wird ignoriert, startsWith):
{ trigger: "@", data: people }
  • Eine synchrone Funktion — verwenden Sie diese, um Ergebnisse selbst zu filtern:
{
trigger: "#",
data: query => tags.filter(t =>
t.label.toLowerCase().startsWith(query.toLowerCase())
)
}
  • Eine asynchrone Funktion — verwenden Sie diese für die serverseitige Suche:
{
trigger: "+",
data: async query => {
const res = await fetch(`/api/users?q=${encodeURIComponent(query)}`);
const users = await res.json();
return users.map(u => ({
id: String(u.id),
label: u.name,
url: u.website
}));
}
}

Verwandtes Beispiel: RichText. Erwähnungen, Tags und asynchrone Suche

Token-Darstellung

Wenn der Benutzer ein Element aus dem Dropdown auswählt, fügt RichText es als <a>-Element mit zwei Datenattributen ein:

<a 
data-token="@"
data-token-id="alice"
href="mailto:alice@example.com">@Alice</a>

Das Token ist ein einzelner nicht bearbeitbarer Knoten. Backspace löscht es in einem Schritt. RichText speichert das Feld url in href, sodass Strg+Klick auf das Token dem Link folgt.

Sie können Tokens mit dem Selektor data-token gestalten:

.wx-editor-content a[data-token="@"][data-token-id="alice"] {
background: #fb8500;
color: #fff;
border-radius: 3px;
padding: 0 2px;
}

Verwandte Beispiele:

Trigger-Zeichen ausblenden

Setzen Sie showTrigger: false auf einem Trigger, um nur die Element-Beschriftung ohne das Trigger-Symbol einzufügen:

{
trigger: "/",
data: commands,
showTrigger: false
}

Tastaturinteraktion

Im Vorschlag-Dropdown können Sie die folgenden Tastenkürzel verwenden:

  • / — zwischen Elementen navigieren
  • Enter — das aktive Element einfügen
  • Escape — das Dropdown schließen ohne einzufügen

Vorschlags-Events abhören

Drei Events stellen den Dropdown-Lebenszyklus über den Event Bus bereit:

  • insert-token — wird ausgelöst, wenn ein Benutzer ein Element auswählt
  • show-suggest — wird ausgelöst, wenn das Dropdown geöffnet wird
  • hide-suggest — wird ausgelöst, wenn das Dropdown geschlossen wird
const editor = new richtext.Richtext("#root", {
triggers: [{ trigger: "@", data: people }]
});

editor.api.on("insert-token", ({ data, trigger, showTrigger }) => {
console.log(`Inserted ${trigger}${data.label} (id: ${data.id})`);
});

Dropdown-Element anpassen

Standardmäßig zeigt das Dropdown die label-Eigenschaft jedes Elements an. Um benutzerdefinierte Vorschläge darzustellen (z. B. Avatar, Name und E-Mail-Adresse), übergeben Sie eine Vorlage über die Eigenschaft triggerTemplate.

Beispiel

const { template } = richtext;

new richtext.Richtext("#root", {
triggers: [{ trigger: "@", data: people }],
triggerTemplate: template(({ data, trigger }) => `
<div className="user">
<div className="user-name">${trigger}${data.label}</div>
<div className="user-url">${data.url || ""}</div>
</div>
`)
});

Verwandtes Beispiel: RichText. Benutzerdefinierte Dropdown-Vorlage pro Trigger

Benutzerdefinierte Aktion bei Auswahl

Standardmäßig wird ein ausgewähltes Element als Token in das Dokument eingefügt. Um stattdessen eigenen Code auszuführen, fügen Sie dem Trigger einen action-Callback hinzu. RichText entfernt den eingegebenen Trigger-Text und ruft action(item) mit dem ausgewählten Element auf — es wird kein Token eingefügt, sodass Sie selbst entscheiden können, was hinzugefügt wird.

Hinweis

action hat Vorrang vor showTrigger. Wenn action gesetzt ist, wird showTrigger ignoriert.

Emoji einfügen

Ein : Trigger kann ein Emoji einfügen, wobei jedes Element ein benutzerdefiniertes Feld code enthält. Kombinieren Sie action mit triggerTemplate, damit das Dropdown das Emoji statt nur seiner Beschriftung anzeigt:

const { template, Richtext } = richtext;

const emoji = [
{
id: "apple", label: "apple", code: "1F34E"
},
{
id: "blue_car", label: "blue_car", code: "1F699"
},
{
id: "computer", label: "computer", code: "1F4BB"
}
];

const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: emoji, // [{ id: "apple", label: "apple", code: "1F34E" }, ...]
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// das Emoji selbst (nicht nur seine Beschriftung) im Dropdown anzeigen
triggerTemplate: template(({ data }) => `${emojiFromCode(data.code)} ${data.label}`)
});

function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}

Verwandtes Beispiel: RichText. Emoji-Autovervollständigung

Emoji nach Kategorien gruppieren

Wenn der Parameter data eine Funktion ist, sind Sie nicht auf den integrierten label-Abgleich beschränkt. Sie können eigene Filterlogik implementieren und Kategorieüberschriften im Dropdown beibehalten. Fügen Sie Header-Elemente hinzu, die ein label-Feld enthalten, aber kein code-Feld. Die data-Funktion sucht zunächst die passenden Emoji und gibt diese dann zusammen mit den Überschriften der Kategorien zurück, die noch Treffer enthalten:

const { template, Richtext } = richtext;

// Header-Elemente haben kein `code`-Feld; Emoji-Elemente enthalten eines
const emoji = [
{ id: "$smileys", label: "Smileys", category: 1 }, // Kategorie
{ id: "grinning", label: "grinning", code: "1F600", category: 1 },
{ id: "smile", label: "smile", code: "1F604", category: 1 },
{ id: "$animals", label: "Animals", category: 2 }, // Kategorie
{ id: "dog", label: "dog", code: "1F436", category: 2 },
{ id: "cat", label: "cat", code: "1F431", category: 2 }
];

const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: query => {
const matched = emoji.filter(item =>
item.code &&
item.label.toLowerCase().startsWith(query.toLowerCase().trim())
);
const categories = new Set(matched.map(item => item.category));
// passende Emojis behalten plus die Überschriften der Kategorien, die noch Treffer enthalten
return emoji.filter(item =>
item.code ? matched.includes(item) : categories.has(item.category)
);
},
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// Emoji-Zeilen normal und Kategorieüberschriften fett darstellen
triggerTemplate: template(({ data }) =>
data.code ? `${emojiFromCode(data.code)} ${data.label}` : `<b>${data.label}</b>`
)
});

function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}

// Überschriften haben kein `code` — Auswahl auf ihnen ignorieren, damit sie nie eingefügt werden
editor.api.intercept("insert-token", ({ data }) => !!data.code);

Slash-Befehlsmenü hinzufügen

Sie können action verwenden, um ein Slash-Befehlsmenü zu erstellen (wie / in Notion oder Slack). Speichern Sie einen Befehlsnamen in der id jedes Elements, dessen Optionen in einem benutzerdefinierten Feld config, und lassen Sie den Callback ihn mit api.exec ausführen:

// jedes Element speichert einen api.exec-Aktionsnamen in `id` und seine Parameter in `config`
const commands = [
{ id: "set-text-style", label: "Heading 1", config: { tag: "h1" } },
{ id: "insert-list", label: "Bulleted list", config: { type: "bulleted" } },
{ id: "insert-line", label: "Divider" } // keine Konfiguration → `|| {}` wird angewendet
];

const editor = new richtext.Richtext("#root", {
triggers: [
{
trigger: "/",
data: commands,
action: item => editor.api.exec(item.id, item.config || {})
}
]
});

Verwandtes Beispiel: RichText. Slash-Befehle