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