Symbolleiste, Live-Vorschau und WYSIWYG im Textbereich, den Sie bereits haben
Zuletzt aktualisiert:
This translation is older than the English page and may be missing recent changes.
Read the English versionEin Markdown-Editor, der Ihren Textbereich erweitert, anstatt ihn zu ersetzen, sodass Formularübermittlung, Validierung und Pflichtfelder weiterhin funktionieren. WYSIWYG- und einfacher Markdown-Modus, Live-Vorschau, Suchen & Ersetzen, RTL-Unterstützung, Dunkelmodus. Funktioniert eigenständig mit Django, Laravel, Rails, Node.js, PHP und jedem Stack.
Kein Frutjam und kein Tailwind erforderlich. Die Stile sind gebündelt, sodass der Editor in jedes Projekt eingefügt werden kann.
Installation
NPM (Bundler: Vite, Webpack, Rollup usw.)
npm install markdown-text-editor |
1 2 | import MarkdownEditor from 'markdown-text-editor'; new MarkdownEditor('#markdown-editor'); |
TypeScript-Definitionen werden mit dem Paket geliefert, sodass Optionen, Symbolleisteneinträge und Variablenformen ohne zusätzliche Installation überprüft und automatisch vervollständigt werden.
Die Typen sind auch importierbar, was immer dann wichtig ist, wenn Ihre Optionen nicht inline auf der Aufrufseite geschrieben werden. TypeScript prüft nur auf unbekannte Schlüssel für ein direkt übergebenes Objektliteral, sodass bei einer in einer eigenen Variablen gespeicherten Konfiguration ein falsch geschriebener Schlüssel stillschweigend ignoriert wird. Durch das Kommentieren wird der Scheck zurückgesetzt.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import MarkdownEditor, { type MarkdownEditorOptions, type ToolbarEntry } from 'markdown-text-editor'; // Without the annotation this compiles, the editor renders with the default // toolbar, and nothing tells you why. const config: MarkdownEditorOptions = { placeholder: 'Write...', toolbr: ['bold', 'preview'], // Error: did you mean to write 'toolbar'? }; // Building a toolbar conditionally const toolbar: ToolbarEntry[] = ['bold', 'italic']; if (canUpload) toolbar.push({ image: { fileInput: { uploadUrl: '/api/upload' } } }); toolbar.push('preview'); |
Dasselbe gilt für eine Wrapper-Komponente, wo MarkdownEditorOptions ist das, was Sie stattdessen weiterleiten any, also behält derjenige, der Ihren Wrapper verwendet, die Kontrolle.
1 2 3 4 | interface EditorProps { value: string; options?: MarkdownEditorOptions; } |
CDN: ES-Modul
1 2 3 4 | <script type="module"> import MarkdownEditor from 'https://cdn.jsdelivr.net/npm/markdown-text-editor/+esm'; new MarkdownEditor('#markdown-editor'); </script> |
CDN: globales Skript-Tag (IIFE)
Kein Import erforderlich: MarkdownEditor ist automatisch als globale Variable verfügbar.
1 2 3 4 5 6 7 8 9 | <form action="/api/save" method="POST"> <textarea id="markdown-editor" name="content"># Hello World</textarea> <button type="submit">Save Content</button> </form> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script> new MarkdownEditor('#markdown-editor'); </script> |
Demo zum Markdown-Editor
Schnellstart
Übergeben Sie ein Optionsobjekt, um den Editor anzupassen. Alle Optionen sind optional: Lassen Sie alle weg, um den Standardwert zu verwenden.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor', { placeholder: 'Write your markdown...', toolbar: ['heading', 'bold', 'italic', 'strikethrough', 'ul', 'ol', 'checklist', 'blockquote', 'link', 'preview'], }); |
Die Philosophie: „Native-First“
Die meisten Redakteure unterbrechen den Standard-Web-Workflow. MarkdownEditor begrüßt es. Weil es direkt auf einem sitzt <textarea>, müssen Sie keinen neuen Umgang mit Daten erlernen.
- Keine Datenbindung erforderlich: Funktioniert mit
<form method="POST">aus der Box - Standardzugriff: Verwendung
document.getElementById('editor').valuegenau wie eine normale Eingabe. - Backend-Agnostik: Funktioniert mit jedem Backend (Python, Node.js, PHP usw.) wie ein normales Formularfeld
MarkdownEditor vs. EasyMDE / SimpleMDE
Die meisten JavaScript-Markdown-Editoren (EasyMDE, SimpleMDE, CodeMirror-basierte Editoren) verstecken Ihre <textarea> und bearbeiten Sie eine Kopie und schreiben Sie den Inhalt zurück, wenn das Formular gesendet wird. Das funktioniert, bis etwas anderes den Wert benötigt: a required Das Feld, auf das sich der Browser nicht konzentrieren kann, blockiert die Übermittlung vollständig und .value oder FormData Vor dem Senden lesen gibt eine leere Zeichenfolge zurück, die Htmx-, Turbo-, Autosave- und nicht gespeicherte Änderungswächter unterbricht. MarkdownEditor ist anders. Er formatiert den Textbereich, den Sie bereits haben, und belässt ihn als das Feld, in das Sie eingeben, sodass der Wert jederzeit korrekt ist.
| Besonderheit | MarkdownEditor | EasyMDE / SimpleMDE |
|---|---|---|
| Nativer Textbereich bleibt erhalten | ✅ | ❌ Versteckt, als Kopie bearbeitet |
Funktioniert mit required Felder | ✅ | ❌ Browser blockiert das Absenden |
.value Vor dem Absenden korrigieren | ✅ | ❌ Leer, bis das Formular gesendet wird |
Serialisiert mit FormData, htmx, Turbo | ✅ | ❌ Benötigt die eigene API des Editors |
| WYSIWYG-Hybridmodus | ✅ | ❌ |
| Integriertes Suchen und Ersetzen | ✅ | ❌ |
| RTL-Unterstützung | ✅ Eingebaut | Über CodeMirrors direction Option |
| Inline-Ereignishandler (CSP) | ✅ Keine | Manche |
| Dunkler Modus / Thematisierung | ✅ | Beschränkt |
| Bundle-Größe, komprimiert | 53 KB | 107 KB (JS + CSS) |
Framework-Integration
Weil MarkdownEditor das Native beibehält <textarea>Es lässt sich ohne zusätzlichen Code in jedes Backend-Framework integrieren. Ihr Server empfängt den Markdown-Inhalt genau so, wie er es von jedem Standardformularfeld tun würde. Für React und Vue sind einige Zeilen erforderlich, die am Ende dieses Abschnitts behandelt werden.
Django
Fügen Sie ein hinzu class zu Ihrem Textbereichs-Widget und initialisieren Sie den Editor: request.POST['content'] Funktioniert ohne zusätzliche Schritte.
1 2 3 4 5 6 7 8 | # forms.py class PostForm(forms.ModelForm): class Meta: model = Post fields = ['content'] widgets = { 'content': forms.Textarea(attrs={'class': 'markdown-editor'}), } |
1 2 | new MarkdownEditor('.markdown-editor'); // request.POST['content'] contains the markdown on submit |
Laravel
Verwenden f.text_area mit einer Klasse: $request->input('content') erhält den Abschlag direkt.
1 2 | <textarea name="content" class="markdown-editor">{{ old('content') }}</textarea> <script>new MarkdownEditor('.markdown-editor');</script> |
Ruby auf Schienen
Funktioniert mit form_with sofort einsatzbereit: params[:content] enthält den Abschlag. Für Turbo Drive verwenden Sie turbo:load anstatt DOMContentLoaded.
1 2 3 4 5 6 | document.addEventListener('turbo:load', () => { document.querySelectorAll('.markdown-editor:not([data-mde-init])').forEach(el => { el.setAttribute('data-mde-init', 'true'); new MarkdownEditor(el); }); }); |
Node.js / Express
req.body.content erhält den Abschlag beim Absenden des Formulars: kein Synchronisierungsschritt, keine benutzerdefinierte Extraktion.
1 2 3 | <textarea name="content" class="markdown-editor"></textarea> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script>new MarkdownEditor('.markdown-editor');</script> |
PHP
$_POST['content'] funktioniert genau wie mit jedem Standard-Textbereich: Fügen Sie es ein und Ihre vorhandene Formularverarbeitung erfordert keine Änderungen.
1 2 3 4 5 6 | <form method="POST" action="save.php"> <textarea name="content" class="markdown-editor"></textarea> <button type="submit">Save</button> </form> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script>new MarkdownEditor('.markdown-editor');</script> |
Reagieren
Erstellen Sie den Editor in einem Effekt und zerstören Sie ihn beim Unmounten. Verwenden defaultValue statt value: Der Editor schreibt direkt in den Textbereich, sodass eine kontrollierte Bindung die Eingaben des Benutzers überschreiben würde.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { useEffect, useRef } from 'react'; import MarkdownEditor from 'markdown-text-editor'; function MarkdownField({ name, defaultValue = '', onChange }) { const ref = useRef(null); useEffect(() => { const editor = new MarkdownEditor(ref.current, { onChange }); return () => editor.destroy(); }, []); return <textarea ref={ref} name={name} defaultValue={defaultValue} />; } |
Rückkehr editor.destroy() Der Effekt deckt auch StrictMode ab, der Effekte in der Entwicklung zweimal ausführt und andernfalls zwei Editoren auf einem Textbereich belassen würde. Das leere Abhängigkeitsarray ist beabsichtigt: Optionen werden einmal gelesen, wenn der Editor erstellt wird, sodass eine erneute Ausführung des Effekts ihn zerstören und bei jeder Änderung neu erstellen würde.
Vue
Gleiche Idee. Legen Sie den Anfangswert einmal fest onMounted und nicht binden :value, oder jeder Tastendruck, der zurück ausgegeben wird v-model würde den Textbereich überschreiben.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue'; import MarkdownEditor from 'markdown-text-editor'; const el = ref(null); const props = defineProps({ modelValue: { type: String, default: '' } }); const emit = defineEmits(['update:modelValue']); let editor = null; onMounted(() => { el.value.value = props.modelValue; editor = new MarkdownEditor(el.value, { onChange: value => emit('update:modelValue', value) }); }); onBeforeUnmount(() => editor?.destroy()); </script> <template><textarea ref="el"></textarea></template> |
Verwendet als <MarkdownField v-model="content" />. In einfacher Form können Sie überspringen v-model vollständig und lesen Sie den Wert aus dem Textbereich beim Senden, wie bei jedem anderen Framework.
Konfiguration
Sie können das Verhalten und die Benutzeroberfläche des Editors vollständig anpassen, indem Sie eine übergeben options Objekt. Wenn Sie eine Option weglassen, wird der Standardwert verwendet.
Optionen werden einmal gelesen, wenn der Editor erstellt wird. Eine nachträgliche Änderung hat keine Auswirkung: Anruf destroy() und erstellen Sie stattdessen einen neuen Editor.
| Eigentum | Typ | Standard | Zweck |
|---|---|---|---|
mode | string | 'plain' | Legt die anfängliche Ansicht fest. Verwenden Sie Hybrid für ein WYSIWYG-Erlebnis oder Plain für reine Syntax. |
placeholder | string | 'Write...' | Text, der angezeigt wird, wenn der Editor leer ist. |
toolbar | array | [...] | Definiert, welche Werkzeuge in welcher Reihenfolge angezeigt werden. |
footer | falsch | Objekt | alles sichtbar | Steuert die Statusleiste, die unterhalb des Editors angezeigt wird. Stellen Sie auf ein false um es ganz auszublenden oder ein Objekt zu übergeben, um einzelne Statistiken umzuschalten. |
theme | string | inherited | Legt explizit das Editor-Thema fest (hell, dunkel, schneebeere, dunkelbeere). Wenn es weggelassen wird, erbt der Editor data-theme vom nächsten Vorfahrenelement oder dem <textarea> selbst. |
minHeight | number | 200 | Mindesthöhe in Pixel, auf die der Editor verkleinert wird, wenn der Inhalt kurz ist. Passt zu maxHeight , um den Bereich für die automatische Vergrößerung festzulegen. |
maxHeight | number | 500 | Maximale Höhe in Pixel, auf die der Editor im Nicht-Vollbildmodus wachsen kann. Sobald der Inhalt diese Höhe überschreitet, erscheint im Editor eine Bildlaufleiste. Der Editor verfügt außerdem über einen Ziehgriff, sodass Benutzer die Größe manuell über diese Grenze hinaus ändern können. |
renderer | function | marked | Ersetzt den für die Vorschau verwendeten Markdown-Parser. Empfängt die Markdown-Zeichenfolge und muss eine HTML-Zeichenfolge zurückgeben. |
sanitizer | function | DOMPurify | Ersetzt den HTML-Sanitizer. Empfängt den gerenderten HTML-Code und muss den sicheren HTML-Code zur Anzeige zurückgeben. |
onChange | function | undefined | Bei jeder Inhaltsänderung wird ein Rückruf ausgelöst: Eingabe, Aktionen in der Symbolleiste, Rückgängigmachen/Wiederherstellen und Fortsetzung der Liste. Empfängt den aktuellen Markdown-String als einziges Argument. |
labels | object | undefined | Übersetzungen für die Editor-eigene Schnittstelle, verschlüsselt durch die englische Zeichenfolge. Alles, was Sie weglassen, bleibt auf Englisch. |
🛠 Anpassung der Symbolleiste
Die Symbolleiste ist modular aufgebaut. Durch Modifizieren des Arrays können Sie ein minimales Erlebnis oder eine leistungsstarke Suite mit vollem Funktionsumfang schaffen.
Verfügbare Tools
| Kategorie | Werkzeugschlüssel |
|---|---|
| Typografie | heading, bold, italic, strikethrough, blockquote |
| Listen | ul (bullet), ol (numbered), checklist |
| Code | code (im Einklang), codeblock (eingezäunter Block) |
| Einlagen | hr (horizontale Regel), table (Tabellenvorlage) |
| Medien | link, image |
| Bearbeitung | undo, redo, indent, outdent |
| Sicht | preview |
| Vorlagen | { variables: [...] }, inline konfiguriert |
Werkzeugreferenz
| Werkzeug | Beschreibung |
|---|---|
heading | Öffnet ein Dropdown-Menü zur Auswahl der Überschriftenebene H1–H6 |
bold | Aktiviert die fette Textformatierung. |
italic | Aktiviert die kursive Textformatierung. |
strikethrough | Ermöglicht das Durchstreichen von Text. |
ol | (Geordnete Liste): Konvertiert Text in ein nummeriertes Listenformat. |
ul | (Ungeordnete Liste): Wandelt Text in eine Aufzählungspunktliste um. |
checklist | Fügt Ihrem Text Kontrollkästchen hinzu, wodurch er sich hervorragend für Aufgaben, To-Do-Listen oder die Verfolgung des Abschlussstatus eignet. |
blockquote | Markieren Sie zitierten oder hervorgehobenen Text. |
code | Umschließt ausgewählten Text für Inline-Code in einzelne Backticks. Durch erneutes Klicken werden die Backticks entfernt. |
codeblock | Umschließt ausgewählten Text in einen umzäunten Codeblock mit drei Backticks. Durch erneutes Klicken werden die Zäune entfernt. |
hr | Fügt ein --- horizontale Linie an der Cursorposition in einer eigenen Zeile. |
table | Fügt an der Cursorposition eine Starter-2x3-Markdown-Tabellenvorlage ein. |
image | Ermöglicht das Einfügen von Bildern über die Markdown-Syntax. |
link | Ermöglicht das Hinzufügen von Hyperlinks zu Ihrem Text. |
undo | Um die letzten Änderungen rückgängig zu machen. |
redo | Um die letzten rückgängig gemachten Änderungen erneut anzuwenden. |
indent | Um die Einrückungsebene zu erhöhen. |
outdent | Zum Verringern der Einrückungsebene. |
preview | Schaltet eine Vollbild-Vorschau nebeneinander um. Kontrollkästchen im Vorschaubereich sind anklickbar und aktualisieren die Markdown-Quelle sofort. Drücken Sie Escape, um den Vollbildmodus zu verlassen. Wenn ein fester Header den Editor im Vollbildmodus abdeckt, siehe --mte-fullscreen-z-index. |
💡 Umsetzungstipps:
- Neuordnung: Die Schaltflächen werden genau in der Reihenfolge angezeigt, in der Sie sie im Array auflisten
- Entfernen: Lassen Sie einfach einen beliebigen Schlüssel weg (z
image) aus dem Array, um diese Funktion für den Benutzer vollständig zu deaktivieren - Nativer Fallback: Wenn Sie keinen bereitstellen
placeholderIn JS verwendet das Plugin automatisch dasplaceholderAttribut aus Ihrem HTML<textarea>
🧩 Benutzerdefinierte Tools
Fügen Sie ohne Verzweigung eine eigene Symbolleistenschaltfläche hinzu. Beschreiben Sie es und legen Sie es in die toolbar Array, in welcher Position auch immer Sie es haben möchten.
1 2 3 4 5 6 7 8 9 10 11 | new MarkdownEditor('#markdown-editor', { toolbar: ['bold', 'italic', { custom: { title: 'Callout', icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">…</svg>', action(editor) { editor.insertText('> [!NOTE]\n> Something worth noting'); } } }, 'preview'] }); |
Der title wird zum Tooltip und zur CSS-Klasse der Schaltfläche, daher kann diese als formatiert werden .callout-btn, genau wie die integrierten Tools.
Mehrere Werkzeuge
Fügen Sie so viele hinzu, wie Sie möchten. Jedes ist ein eigener Eintrag im Array, sodass Sie sie einzeln platzieren können und zwischen integrierten Werkzeugen platziert werden können, anstatt an einem Ende gruppiert zu werden.
1 2 3 4 5 6 7 | toolbar: [ 'bold', 'italic', { custom: { title: 'Callout', icon: svg1, action: insertCallout } }, 'ul', 'ol', { custom: { title: 'Signature', icon: svg2, action: insertSignature } }, 'preview' ] |
Geben Sie jedem eine eigene Note title. Zwei Tools, die einen Titel teilen, würden sich eine CSS-Klasse teilen, und ein Tool ohne einen solchen greift auf diese zurück .custom-btn.
Optionen
| Eigentum | Typ | Zweck |
|---|---|---|
title | string | Erforderlich. Tooltip-Text und die Quelle der CSS-Klasse der Schaltfläche. Übersetzbar durch labels. |
action | function | Erforderlich. Empfängt (editor, event). Das Click-Ereignis wird weitergegeben, damit ein Tool, das einen Dialog öffnet, es weitergeben kann MarkdownEditor.modal. |
icon | string | Inline-SVG für die Schaltflächenoberfläche. |
shortcut | string | Eine Tastenkombination wie z Ctrl+Shift+K. Wird der QuickInfo hinzugefügt und hat Vorrang vor einer integrierten Funktion, die dieselben Tasten verwendet. |
Ein Werkzeug ohne action wird mit einer Konsolenwarnung übersprungen, anstatt die Symbolleiste zu beschädigen. Es rendert keine Schaltfläche und es ist shortcut, falls es eines deklariert hat, ist ebenfalls nicht registriert.
Arbeiten mit den Inhalten
Verwenden editor.insertText() anstatt selbst in den Textbereich zu schreiben. Es ersetzt die Auswahl, stellt den Fokus wieder her, verschiebt die Einfügemarke, scrollt, rendert die Vorschau neu und wird ausgelöst onChange. Das Rückgängigmachen funktioniert weiterhin, da die Bearbeitung über den normalen Pfad erfolgt.
1 2 3 4 5 6 7 8 | action(editor) { const textarea = editor.usertextarea; const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd); const wrapped = `==${selected || 'highlight'}==`; // (text, where the caret lands, characters to leave outside the selection) editor.insertText(wrapped, wrapped.length, 0); } |
Verknüpfungen
1 2 3 4 5 6 | { custom: { title: 'Highlight', icon: '<svg>…</svg>', shortcut: 'Ctrl+Shift+H', action: (editor) => editor.insertText('====', 2, 2) }} |
Der Tooltip wird zu „Hervorheben (Strg+Umschalt+H)“. Werkzeugverknüpfungen werden vor den integrierten überprüft, sodass ein benutzerdefiniertes Werkzeug gezielt eine Kombination übernehmen kann, die der Editor sonst verarbeiten würde.
Tools, die ein eigenes Markup benötigen
Ein Dropdown oder ein Dialog kann nicht deklarativ beschrieben werden, also schreiben Sie stattdessen eine Klasse. Verlängern MarkdownEditor.Tool, Satz this.button im Konstruktor und implementieren applySyntax().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class EmbedTool extends MarkdownEditor.Tool { constructor(editor) { super(editor, 'Embed video'); // tooltip, and .embed-video-btn this.shortcut = 'Ctrl+Shift+E'; // optional this.button = this.createButton('<svg>…</svg>'); } applySyntax(event) { const dialog = MarkdownEditor.modal(event, 'fj:max-w-sm', ` <input type="url" class="embed-url fj:me-input fj:w-full"> <button type="button" class="embed-go fj:me-btn fj:me-btn-sm">Insert</button> `, 'Embed'); dialog.querySelector('.embed-go').addEventListener('click', () => { const url = dialog.querySelector('.embed-url').value.trim(); if (url) this.editor.insertText(`\n<iframe src="${url}"></iframe>\n`); dialog.close(); }); } destroy() { // Called by editor.destroy(). Release anything you registered here. } } new MarkdownEditor('#markdown-editor', { toolbar: ['bold', EmbedTool, 'preview'] }); |
Konfiguration mit übergeben { tool: EmbedTool, config: {...} }, das als zweites Argument des Konstruktors eintrifft. Einstellung this.button Zu null rendert nichts, was für ein Tool nützlich ist, das nur in einigen Konfigurationen anwendbar ist.
Eine Sache, die Sie beachten sollten: ToolKonstruktoraufrufe createButton(), also muss alles, was Sie zum Überschreiben benötigen, von dort stammen this.editor, nicht aus einem Feld, das Sie danach zuweisen super().
Der Dialoghelfer
MarkdownEditor.modal ist der Dialog, den die integrierten Link- und Bild-Tools verwenden, sodass ein Tool von Ihnen, das Eingaben sammelt, wie der Rest des Editors aussieht, anstatt ein eigenes Popup zu erfinden. Es gibt die zurück <dialog> Element, bereits geöffnet, das Sie nach Ihren Feldern abfragen und mit dem Sie schließen dialog.close().
1 2 | // (event, size classes, body HTML, aria label) const dialog = MarkdownEditor.modal(event, 'fj:max-w-sm', '…', 'Embed'); |
Übergeben Sie die event dein applySyntax() erhalten. Der Helfer liest ihn, um herauszufinden, von welchem Editor der Klick kam, sodass der Dialog in den Wrapper dieses Editors eingefügt wird und sein Thema übernimmt. Es ersetzt alle bereits in diesem Editor geöffneten Dialoge und entfernt sich beim Schließen selbst aus dem DOM, sodass nichts bereinigt werden muss.
Markdown selbst rendern
Wenn Ihr Tool gerenderte Inhalte einbettet, beispielsweise einen Tooltip-Text, editor.renderMarkdown() erzeugt HTML genau wie die Vorschau und würdigt damit Ihre renderer Und sanitizer.
const html = editor.renderMarkdown('**bold** text'); |
Eine Symbolleiste für Ihren eigenen Textbereich
Wenn ein Dialog Rich-Text sammelt, geben Sie ihm die echten Formatierungswerkzeuge, anstatt sie neu zu erstellen. Die Symbolleiste ist an den von Ihnen übergebenen Textbereich gebunden labels werden vererbt und es wird keine Vorschauschaltfläche hinzugefügt.
1 2 3 | const body = dialog.querySelector('textarea'); const bar = editor.createToolbar(body, ['bold', 'italic', 'strikethrough']); dialog.querySelector('.body-toolbar').appendChild(bar); |
Dadurch wird die Lebensdauer der Symbolleiste nicht verwaltet. Die Schaltflächen werden mit dem Dialogfeld bereinigt, wenn es entfernt wird. Wenn jedoch ein darin enthaltenes Tool seitenweit etwas registriert, einen Dokument-Listener oder einen Timer, geben Sie dies selbst frei, wenn das Dialogfeld geschlossen wird.
Übersetzung
Benutzerdefinierte Tools werden wie integrierte Tools übersetzt, kodiert nach dem Titel, den Sie ihnen gegeben haben.
labels: { 'Callout': 'Aviso', 'Embed video': 'Insertar video' } |
Die CSS-Klasse ist also nicht betroffen .callout-btn bleibt .callout-btn in jeder Sprache.
📊 Fußzeile (Statusleiste)
Die Fußzeile befindet sich unterhalb des Editors und zeigt die Zeile, Spalte des Cursors, die Zeichenanzahl des Dokuments und optional die Wortanzahl an, alles in Echtzeit aktualisiert. Es ist standardmäßig sichtbar und jede Statistik kann unabhängig umgeschaltet werden.
| Schlüssel | Typ | Standard | Beschreibung |
|---|---|---|---|
line | boolean | true | Zeigt die aktuelle Zeilennummer an. |
col | boolean | true | Zeigt die aktuelle Spaltennummer an. |
chars | boolean | true | Zeigt die Gesamtzahl der Zeichen an. |
words | boolean | false | Zeigt die Gesamtzahl der Wörter an. Standardmäßig deaktiviert: auf eingestellt true zu ermöglichen. |
Anwendungsbeispiele
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Default — line, col, and chars visible new MarkdownEditor('#editor'); // Disable the footer entirely new MarkdownEditor('#editor', { footer: false }); // Hide only character count new MarkdownEditor('#editor', { footer: { chars: false } }); // Hide line and column, keep character count new MarkdownEditor('#editor', { footer: { line: false, col: false } }); // Show only line number new MarkdownEditor('#editor', { footer: { col: false, chars: false } }); // Enable word count alongside the defaults new MarkdownEditor('#editor', { footer: { words: true } }); // Show word count only new MarkdownEditor('#editor', { footer: { line: false, col: false, chars: false, words: true } }); |
🔀 Bearbeitungsmodi
MarkdownEditor bietet zwei verschiedene Möglichkeiten zum Schreiben und Formatieren Ihrer Inhalte. Sie können zwischen einer traditionellen syntaxorientierten Ansicht und einem modernen, visuell ausgerichteten Erlebnis wechseln.
plain(Standard*): Eine saubere, leistungsstarke Markdown-Umgebung, in der Syntax (wie**bold**oder# heading) ist sichtbar. Ideal für Entwickler und Markdown-Puristenhybrid: Ein WYSIWYG-inspiriertes Erlebnis, das Formatierungen (Fett, Kursiv, Überschriften) in Echtzeit während der Eingabe wiedergibt und gleichzeitig die zugrunde liegende Markdown-Struktur beibehält.
1 2 3 4 5 6 7 8 9 10 11 12 | // Default initialization (Plain Mode) new MarkdownEditor('#markdown-editor'); // Explicit Plain Mode new MarkdownEditor('#markdown-editor', { mode: 'plain' }); // Hybrid (Visual) Mode new MarkdownEditor('#markdown-editor', { mode: 'hybrid' }); |
Vorschau des Hybrid- und Normalmodus:
Hybridmodus
Visuelle Formatierungen werden während der Eingabe in Echtzeit gerendert.
Einfacher Modus (Standard)
Konzentriert sich auf die reine Markdown-Syntax für ein unkompliziertes Erlebnis.
🌙 Thematisierung
MarkdownEditor erbt sein Thema automatisch von der umgebenden Seite: keine Konfiguration erforderlich. Der Herausgeber liest data-theme vom nächsten Vorfahren bei der Initialisierung, so dass es sofort mit dem Thema Ihrer Website synchronisiert bleibt.
Wie das Thema gelöst wird (Prioritätsreihenfolge)
themeOption: explizite Überschreibung im Optionsobjekt übergebendata-themeauf der<textarea>: direkt auf das Element setzendata-themeauf einem beliebigen Vorfahren: z.B.<html>,<body>, oder ein Wrapper<div>
Verfügbare Themen
'light' (Standard), 'dark', 'snowberry', 'darkberry'
Option 1, erben von <html> oder ein beliebiger Vorfahre (keine Konfiguration)
1 2 3 4 5 6 | <html data-theme="dark"> ... <textarea id="markdown-editor"></textarea> <script> new MarkdownEditor('#markdown-editor'); // picks up dark automatically </script> |
Option 2: einstellen data-theme direkt am <textarea>
1 2 3 4 | <textarea id="markdown-editor" data-theme="dark"></textarea> <script> new MarkdownEditor('#markdown-editor'); </script> |
Option 3: explizit theme Option (überschreibt alles)
1 2 3 | new MarkdownEditor('#markdown-editor', { theme: 'dark' }); |
🎨 Benutzerdefiniertes Design über CSS-Variablen
Sie können das Erscheinungsbild des Editors vollständig anpassen, indem Sie seine CSS-Variablen überschreiben .markdown-editor-wrapper Element oder irgendein [data-theme] Wähler. Alle Farben verwenden das OKLCH-Farbraum für wahrnehmungsmäßig einheitliche Ergebnisse.
| Variable | Zweck | Lichtstandard | Dunkle Standardeinstellung |
|---|---|---|---|
--color-base | Hintergrund des Herausgebers | oklch(100% 0 0) | oklch(10.9% 0 0) |
--color-on-base | Primäre Textfarbe | oklch(22% 0 0) | oklch(98% 0 0) |
--color-primary | Primärer Akzent (Symbolleiste aktiv, Links) | oklch(51.1% .262 277) | oklch(66.4% .184 286) |
--color-on-primary | Text auf primärfarbigen Oberflächen | oklch(96.2% .018 272) | oklch(10% .01 270) |
--color-secondary | Sekundärer Akzent | oklch(59.1% .293 323) | oklch(65% .18 220) |
--color-accent | Hervorhebungsakzent (Inline-Code, kursiv) | oklch(54.1% .281 293) | oklch(75% .18 50) |
--color-neutral | Neutrale Flächen (Ränder, Trennwände) | oklch(15% 0 0) | oklch(85% 0 0) |
--color-error | Farbe des Fehlerstatus | oklch(57.7% .245 27) | oklch(60% .22 30) |
--border-radius | Eckenabrundung des Editorrahmens | 0.25rem |
Beispiel für ein benutzerdefiniertes Theme
Überschreiben Sie alle Variablen .markdown-editor-wrapper nach der Initialisierung des Editors oder definieren Sie eine benutzerdefinierte Datei [data-theme] Block in Ihrem Stylesheet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* Override individual variables */ .markdown-editor-wrapper { --color-primary: oklch(60% 0.2 30); /* orange accent */ --border-radius: 0.5rem; } /* Or define a full custom theme */ [data-theme="brand"] .markdown-editor-wrapper, .markdown-editor-wrapper[data-theme="brand"] { --color-base: oklch(15% 0.01 250); --color-on-base: oklch(95% 0 0); --color-primary: oklch(65% 0.22 145); /* green */ --color-on-primary: oklch(10% 0 0); --color-accent: oklch(75% 0.18 60); --color-neutral: oklch(80% 0 0); --border-radius: 0.75rem; } |
new MarkdownEditor('#markdown-editor', { theme: 'brand' }); |
🌐 Schnittstellensprache
Der eigene Text des Editors, Tooltips, Menüelemente, modale Felder und Schaltflächen sind standardmäßig Englisch. Pass a labels Objekt, um es zu übersetzen. Schlüssel sind die englischen Zeichenfolgen, so wie gettext funktioniert, sodass Sie nur auflisten, was Sie ändern möchten, und alles, was fehlt, wird auf Englisch zurückgesetzt.
1 2 3 4 5 6 7 8 9 10 11 12 13 | new MarkdownEditor('#markdown-editor', { labels: { 'Bold': 'Gras', 'Italic': 'Italique', 'Heading': 'Titre', 'Link': 'Lien', 'Image link': 'Lien de l\'image', 'URL': 'URL', 'Alt text': 'Texte alternatif', 'Apply': 'Appliquer', 'Uploading...': 'Téléversement...', }, }); |
Dies ist neben rechts-nach-links geschriebenen Inhalten am wichtigsten. Arabisch, Urdu und Farsi werden für sich genommen korrekt angezeigt, aber eine Symbolleiste, in der immer noch „Fett“ über von rechts nach links geschriebenem Text steht, ist nur zur Hälfte übersetzt.
🏷 Variablen
Fügt ein Dropdown-Menü in der Symbolleiste zum Einfügen von Platzhaltern hinzu. Nützlich, wenn die Person, die ein Dokument schreibt, nicht der Entwickler ist, der die Platzhaltersyntax definiert hat, wie bei E-Mail-, Rechnungs- oder Vertragsvorlagen: Sie wählt einen lesbaren Namen und die richtige Syntax wird für sie eingefügt.
1 2 3 4 5 6 7 8 9 | new MarkdownEditor('#markdown-editor', { toolbar: ['bold', 'italic', 'link', { variables: [ { label: 'Customer Name', value: '{{customer.name}}' }, { label: 'Invoice No', value: '{{invoice.number}}' } ]}, 'preview' ] }); |
Das Tool wird inline im konfiguriert toolbar Array, sodass die Position zwischen den anderen Schaltflächen Ihnen überlassen bleibt. Die Schaltfläche listet die Beschriftungen auf, und wenn Sie auf eine klicken, werden diese eingefügt value am Cursor und ersetzt jede Auswahl. Wenn die Liste leer ist, wird nichts gerendert.
Beispielwerte in der Vorschau
Ein Eintrag gegeben a sample zeigt dieses Beispiel in der Vorschau an, während der Textbereich den echten Platzhalter behält. Einträge ohne eins erscheinen wie geschrieben, Sie können also beides mischen.
1 2 3 4 5 6 7 | { variables: [ { label: 'Customer Name', value: '{{customer.name}}', sample: 'Hannes' }, { label: 'Invoice No', value: '{{invoice.number}}' } ]} // textarea : Hi {{customer.name}}, invoice {{invoice.number}} // preview : Hi Hannes, invoice {{invoice.number}} |
Gruppierung
Geben Sie einen Eintrag ein items statt eines value um einen Abschnitt mit Überschrift darzustellen. Gruppierte und flache Einträge können in einer Liste gemischt werden.
1 2 3 4 5 6 7 8 9 10 | { variables: [ { label: 'Today', value: '{{today}}', sample: '10 September 2026' }, { label: 'Customer', items: [ { label: 'Name', value: '{{customer.name}}', sample: 'Hannes' }, { label: 'Email', value: '{{customer.email}}', sample: 'hannes@example.com' } ]}, { label: 'Invoice', items: [ { label: 'Number', value: '{{invoice.number}}' } ]} ]} |
Wissenswertes
- Der Editor löst niemals Variablen auf. Er fügt Text ein und Ihre Anwendung ersetzt später reale Werte, normalerweise serverseitig.
samplewirkt sich nur darauf aus, was in der Vorschau angezeigt wird. - Beschriftungen werden als einfacher Text angezeigt, daher wird das Markup in einer Beschriftung nie gerendert.
- Fehlerhafte Einträge werden übersprungen statt ausgelöst, und die Schaltfläche wird überhaupt nicht gerendert, wenn nichts Verwendbares konfiguriert ist.
🖋 Benutzerdefinierter Renderer
Die Vorschau wird mit gerendert markiert und desinfiziert mit DOMPurify. Beide können ausgetauscht werden. Verwenden Sie diese Option, wenn Ihre Anwendung Markdown bereits mit einer anderen Bibliothek rendert und Sie möchten, dass die Vorschau genau mit der Produktion übereinstimmt.
Bei beiden Optionen handelt es sich um einfache Funktionen, die einen String annehmen und zurückgeben, sodass jeder Parser und jedes Sanitizer funktioniert.
1 2 3 4 5 6 7 8 9 | import MarkdownIt from 'markdown-it'; import taskLists from 'markdown-it-task-lists'; import MarkdownEditor from 'markdown-text-editor'; const md = new MarkdownIt({ linkify: true, breaks: true }).use(taskLists); new MarkdownEditor('#markdown-editor', { renderer: markdown => md.render(markdown) }); |
DOMPurify wird weiterhin auf der Ausgabe ausgeführt, sodass Sie den XSS-Schutz beibehalten, ohne etwas konfigurieren zu müssen.
Benutzerdefiniertes Desinfektionsmittel
Wird nur benötigt, wenn die Standardeinstellung etwas entfernt, das Ihr Renderer ausgibt. DOMPurify entfernt <iframe> standardmäßig, daher muss es für Videoeinbettungen explizit zugelassen werden. DOMPurify muss in Ihren eigenen Code importiert werden, da die mit dem Editor gebündelte Kopie intern ist.
1 2 3 4 5 6 7 8 9 | import DOMPurify from 'dompurify'; new MarkdownEditor('#markdown-editor', { renderer: markdown => md.render(markdown), sanitizer: html => DOMPurify.sanitize(html, { ADD_TAGS: ['iframe'], ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder'] }) }); |
Laden Sie DOMPurify mit einem Skript-Tag anstelle eines Bundlers zusammen mit dem Editor:
1 2 | <script src="https://cdn.jsdelivr.net/npm/dompurify"></script> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> |
Wissenswertes
- Nur Vorschau. Die Live-Formatierung des Hybridmodus verwendet einen separaten internen Renderer und ist nicht betroffen.
- Aufgabenlisten benötigen Plugin-Unterstützung. Anklickbare Kontrollkästchen werden durch Suchen gefunden
input[type="checkbox"]in der Ausgabe, daher ist ein Abschlag erforderlichmarkdown-it-task-lists. Der Editor protokolliert eine Warnung, wenn er die Aufgabenlistensyntax und keine Kontrollkästchen erkennt. - Beide müssen synchron sein und einen String zurückgeben. Ein
asyncFunktion schreibt[object Promise]in die Vorschau. - Der Austausch des Desinfektionsmittels ersetzt Ihren Schutz. Eine Durchreiche wie z.B
html => htmldeaktiviert die Bereinigung vollständig und ist nur für vollständig vertrauenswürdige Inhalte sicher.
🎨 Interne Elemente gestalten
CSS-Variablen decken die meisten Themen ab, da sie erben, also setzen Sie eine ein .markdown-editor-wrapper erreicht die Symbolleiste, Schaltflächen, Vorschau und Fußzeile. Greifen Sie nur dann nach einem Klassennamen, wenn keine Variable das bereitstellt, was Sie benötigen.
1 2 3 4 5 | /* Variables set on the wrapper inherit down to every child */ .markdown-editor-wrapper { --border-radius: 12px; /* rounds the editor and its toolbar buttons */ --color-primary: oklch(60% 0.2 30); } |
Klassenreferenz
Diese Klassennamen sind stabil und können sicher verwendet werden.
| Klasse | Element |
|---|---|
.markdown-editor-wrapper | Äußerer Container, der den gesamten Editor umschließt |
.toolbar | Symbolleiste über dem Bearbeitungsbereich |
.markdown-btn | Individuelle Schaltfläche in der Symbolleiste |
.preview-btn | Die Schaltfläche zum Umschalten zwischen Vorschau und Vollbild |
.editor-layout | Raster, das den Bearbeitungsbereich und die Vorschau nebeneinander enthält |
.textarea-wrapper | Wrapper um den Bearbeitungsbereich |
.editor-textarea | Das zugrunde liegende Textbereichselement |
.display-layer | Gerenderte Formatierungsebene, nur Hybridmodus |
.preview-wrapper | Vorschauspalte |
.preview-content | Gerenderter Markdown in der Vorschau |
.editor-footer | Statusleiste unterhalb des Editors |
.find-replace-panel | Panel suchen und ersetzen |
1 2 3 4 5 6 7 8 9 10 | /* Some variables are set by the component on itself, which beats an inherited value. Target the element directly for those. */ .markdown-editor-wrapper .markdown-btn { --btn--font-size: 0.875rem; } /* And use classes for anything no variable exposes */ .markdown-editor-wrapper .toolbar { border-bottom: 2px solid oklch(60% 0.2 30); } |
Ausrichtung auf einen Redakteur
Wenn Sie mehrere Redakteure auf einer Seite haben, zielen Sie auf einen von ihnen ab data-editor. Der Wrapper spiegelt seine ID wider <textarea>, Also <textarea id="notes"> gibt dir [data-editor="notes"]. Die ID selbst bleibt also im Textbereich getElementById funktioniert weiter.
1 2 3 4 | /* one editor only */ [data-editor="notes"] { --border-radius: 0; } |
🪟 Vollbild & Layering (Z-Index)
Im Vollbildmodus verwendet der Editor z-index: 10000, wodurch die Ebenen gelöscht werden, die die meisten UI-Frameworks für feste Header und Overlays reservieren. Wenn der Editor immer noch von einer festen Kopfzeile oder Seitenleiste abgedeckt wird, erhöhen Sie diesen Wert.
Überschreiben Sie es mit --mte-fullscreen-z-index. Der Wert gilt nur im Vollbildmodus und erbt. Wenn Sie ihn also auf einen beliebigen Vorfahren festlegen, werden alle darunter liegenden Editoren abgedeckt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* every editor on the page */ .markdown-editor-wrapper { --mte-fullscreen-z-index: 20000; } /* one section only - the value inherits down */ #admin-panel { --mte-fullscreen-z-index: 20000; } /* a single editor, by its textarea id */ [data-editor="notes"] { --mte-fullscreen-z-index: 20000; } |
Inhalts-API
Eine der Kernstärken von MarkdownEditor besteht darin, dass es das zugrunde liegende behält <textarea> perfekt synchronisiert. Ganz gleich, ob Sie ein modernes JavaScript-Framework oder ein traditionelles Backend wie Django, PHP oder Laravel verwenden, der Workflow bleibt einfach und nativ.
Inhalte lesen und schreiben
1. The Native Way (empfohlen)
Da der Editor einen Standardtextbereich erweitert, können Sie bekannte DOM-Methoden verwenden. Dies ist der schnellste Weg, mit Ihren Daten zu interagieren, ohne eine neue API zu erlernen.
1 2 3 4 5 | // Retrieve content via ID const markdown = document.getElementById('markdown-editor').value; // Set content via ID (The editor UI updates automatically) document.getElementById('markdown-editor').value = "# New Heading Content"; |
2. Verwenden einer Variablenreferenz
Wenn Sie einen Verweis auf das Textarea-Element haben, können Sie es direkt verwenden: Es ist keine bibliotheksspezifische API erforderlich.
1 2 3 4 5 6 7 | const textarea = document.getElementById('markdown-editor'); // Retrieve content const markdown = textarea.value; // Set content (the editor UI reflects this immediately) textarea.value = "## Updated via JS"; |
3. Festlegen des anfänglichen Inhalts serverseitig
Die empfohlene Methode zum Festlegen des anfänglichen Inhalts ist direkt im <textarea> HTML: Dies funktioniert natürlich mit jedem Backend-Framework (Django, Laravel, Rails, PHP usw.) und der Editor rendert es automatisch bei init.
1 2 | <!-- Recommended: set content server-side --> <textarea id="markdown-editor"># Hello World</textarea> |
Um Inhalte zur Laufzeit zu lesen oder zu aktualisieren, verwenden Sie die native textarea Wert. Anruf editor.render() nach einem Update, um die Vorschau- und Hybridebene zu aktualisieren.
1 2 3 4 5 6 7 8 | const textarea = document.getElementById('markdown-editor'); // Read const markdown = textarea.value; // Update at runtime textarea.value = '# New content'; editor.render(); |
4. Abbau des Editors: destroy()
Anruf editor.destroy() um den Editor-DOM-Wrapper zu entfernen und das Original wiederherzustellen <textarea> an seine Position im Dokument. Nützlich in Single-Page-Anwendungen beim Unmounten einer Ansicht.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor'); // Remove the editor and restore the plain textarea editor.destroy(); |
Auf Veränderungen reagieren mit onChange
Übergeben Sie eine onChange Rückruf, um bei jeder Inhaltsänderung benachrichtigt zu werden. Empfängt die aktuelle Markdown-Zeichenfolge.
1 2 3 4 5 | const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { console.log('Content changed:', value.length, 'characters'); } }); |
Entwurf automatisch speichern mit localStorage
Verwenden onChange um bei jedem Tastendruck einen Entwurf zu speichern. Stellen Sie es wieder her, indem Sie den Textbereich vorab ausfüllen, bevor Sie den Editor initialisieren.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | const DRAFT_KEY = 'my-page-draft'; // Restore saved draft before init (only if textarea starts empty) const textarea = document.getElementById('markdown-editor'); const saved = localStorage.getItem(DRAFT_KEY); if (saved && !textarea.value) textarea.value = saved; // Save on every change const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { localStorage.setItem(DRAFT_KEY, value); } }); // Clear draft after successful form submission document.querySelector('form').addEventListener('submit', () => { localStorage.removeItem(DRAFT_KEY); }); |
Formularübermittlung
Weil MarkdownEditor direkt auf dem nativen basiert <textarea>Es ist sofort mit jedem Backend-Framework (Django, Laravel, PHP, Ruby on Rails usw.) kompatibel.
Hier kommt die „Native-First“-Philosophie zum Tragen. Sie müssen die Daten vor dem Absenden eines Formulars nicht manuell synchronisieren. Der Browser behandelt den Editor genau wie ein Standard-Eingabefeld.
1 2 3 4 5 6 7 8 9 10 11 12 | <form method="POST" action="/api/submit"> <textarea id="markdown-editor" name="content" class="h-48" rows="5"> # Initial Content </textarea> <button type="submit">Submit to Server</button> </form> <script> // Just initialize it. That's it. new MarkdownEditor('#markdown-editor'); </script> |
Notiz: Initialisierung des MarkdownEditor-Plugins erforderlich
Verwenden Sie einfach ein Standard-HTML <form>. Der name Das Attribut im Textbereich wird von Ihrem Server verwendet, um den Inhalt zu identifizieren.
🚀 Warum es ein Game-Changer für Backends ist
Da der Herausgeber das Native bewahrt <textarea> Verhalten verarbeitet Ihr Server die Daten als Standardzeichenfolge. Es ist keine zusätzliche Logik erforderlich: Nein preventDefault() und kein Handbuch FormData Konstruktion.
💡 Warum dies ein „Killer-Feature“ ist:
Die meisten Editoren (wie Quill, Editor.js, simpleMDE, easyMDE) speichern Daten in komplexen JSON-Strukturen. Wenn ein Entwickler diese verwendet, muss er sein Datenbankschema und seine Rendering-Logik neu schreiben.
Mit MarkdownEditor kann ein Entwickler eine alte Website durch eine einfache ersetzen <textarea> mit Ihrem Editor, und das Backend weiß nicht einmal, dass es sich geändert hat. Es erhält einfach den gleichen Rohtext wie immer, aber der Benutzer erhält ein zehnmal besseres Erlebnis.
| Rahmen / Sprache | So greifen Sie auf den Markdown-Inhalt zu |
|---|---|
| PHP | $_POST['content'] |
| Django | request.POST.get('content') |
| Node.js (Express) | req.body.content |
| Laravel | $request->input('content') |
| Ruby auf Schienen | params[:content] |
🖼️ Erweiterter Bild-Upload
Die native Handhabung von Bild-Uploads: Anstatt sich auf langsame, speicherintensive Base64-Strings zu verlassen, ist dies ein erheblicher Gewinn für Leistung und SEO.
Einfügen und ablegen
Fügen Sie einen Screenshot ein oder ziehen Sie eine Bilddatei in den Editor und sie wird über denselben Endpunkt wie die Symbolleistenschaltfläche hochgeladen. Ein Platzhalter wird sofort angezeigt, sodass der Editor nie eingefroren aussieht, und er wird durch den tatsächlichen Pfad ersetzt, sobald der Upload erfolgt. Wenn der Upload fehlschlägt, wird der Platzhalter durch eine sichtbare Markierung ersetzt und verschwindet nicht lautlos.
Das braucht uploadUrl unten konfiguriert. Ohne sie führt das Einfügen eines Bilds zu nichts und der Editor protokolliert eine Warnung, die erklärt, was hinzugefügt werden soll, da die Alternative ein Base64-String in Ihrer Datenbank wäre.
Es werden mehrere Dateien gleichzeitig hochgeladen, sodass die Bilder in der Reihenfolge landen, in der sie eingegangen sind.
Konfigurationsoptionen
Das Bildtool unterstützt a fileInput Konfiguration für direkte Server-Uploads.
accept: Definieren Sie ein Array zulässiger Bildformate (z. B. „webp“, „avif“).uploadUrl: Geben Sie den Backend-Endpunkt an, an dem dieFileDas Objekt wird per gesendetPOSTparams: Optionales Objekt zum Senden zusätzlicher Daten (wie CSRF-Tokens, Benutzer-IDs oder Ordnernamen) zusammen mit der Bilddatei
Anwendungsbeispiel (Vollständige Konfiguration)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const options = { placeholder: 'Start writing...', toolbar: [ 'link', { image: { fileInput: { accept: ['webp', 'avif'], // restrict the image upload format uploadUrl: '/api/upload', // Your upload endpoint params: { _token: 'your_csrf_token_here', // Essential for Laravel/Django folder: 'blog_posts' } }, // Supports boolean: true/false OR object: { required: true } altInput: { required: true } } }, 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
📡 Serverintegration
Die Anfrage
Der Herausgeber sendet eine POST Anfrage als multipart/form-data. Standardmäßig umfasst es:
image_file: Das eigentliche Dateiobjektimage_alt: Der vom Benutzer eingegebene Alternativtext- ... plus alle in der definierten benutzerdefinierten Daten
paramsObjekt
Die erforderliche Antwort
Um einen erfolgreichen Upload zu bestätigen und das Bild in den Editor einzufügen, muss Ihr Server die folgende JSON-Struktur zurückgeben:
1 2 3 4 | { "success": true, "image_path": "https://cdn.yourdomain.com/uploads/image.webp" } |
Hinweis: Stellen Sie sicher, dass Sie den Schlüssel verwenden image_path für die URL des hochgeladenen Bildes.
Sie können auch zurückkehren image_alt, der nur dann als Vorschlag verwendet wird, wenn der Benutzer das Alt-Feld leer gelassen hat. Alles, was sie selbst eingegeben haben, gewinnt immer, sodass ein Server, der Alternativtext aus dem Dateinamen oder der Bilderkennung ableitet, ihn anbieten kann, ohne eine echte Beschreibung zu überschreiben.
1 2 3 4 5 | { "success": true, "image_path": "https://cdn.yourdomain.com/uploads/image.webp", "image_alt": "Two people looking at a laptop" } |
Bei Misserfolg kehren Sie zurück success: false mit einem error oder message Zeichenfolge. Dieser Text wird dem Benutzer angezeigt, also machen Sie ihn zu etwas, auf das er reagieren kann.
Bild-Alt-Text-Validierung (altInput)
Um sicherzustellen, dass Ihre Inhalte zugänglich und SEO-freundlich bleiben, erzwingt MarkdownEditor standardmäßig die Alt-Text-Validierung.
- Standardverhalten: Wenn
altInputist nicht definiert, der Standardwert ist{ required: true } - Barrierefreiheit erzwingen: Benutzer können kein Bild einfügen, bis eine Alternativbeschreibung bereitgestellt wird
1. Standard (keine Konfiguration erforderlich)
1 2 3 4 | // Alt text is REQUIRED by default image: { fileInput: { uploadUrl: '/api/upload' } } |
2. Kurzschrift (Validierung deaktivieren)
Wenn Sie Bilder ohne Beschreibung zulassen möchten, setzen Sie einfach den booleschen Wert auf false.
1 2 3 | image: { altInput: false // Users can now skip the alt text field } |
3. Objektbasiert (explizit)
1 2 3 4 5 | image: { altInput: { required: false // Disables alt text validation — users can skip the alt field } } |
Standardbildnutzung (Nr fileInput)
Wenn fileInput nicht konfiguriert ist, verwendet der Editor standardmäßig ein einfaches URL-basiertes Modal. Dies ist ideal, wenn Ihre Benutzer hauptsächlich auf externe Image-Hosts verlinken.
1 2 3 4 5 6 7 8 | const options = { toolbar: [ 'link', 'image', 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
💡 Warum Parameter verwenden?
In Frameworks wie Laravel oder Django können Sie keine Dateien ohne CSRF-Token hochladen. Durch Hinzufügen _token zum params Objekt, Ihre Anfrage durchläuft die Sicherheits-Middleware des Backends nahtlos und behält die „Zero Logic“-Philosophie für Ihre serverseitigen Controller bei.
⌨️ Tastaturkürzel
Gängige Formatierungsaktionen können direkt über die Tastatur ausgelöst werden, ohne die Symbolleiste zu berühren. Jede Verknüpfung wird auch im Tooltip der entsprechenden Symbolleistenschaltfläche angezeigt.
| Abkürzung | Aktion |
|---|---|
Ctrl + B / ⌘ B | Umschalten Fett |
Ctrl + I / ⌘ I | Kursiv umschalten |
Ctrl + K / ⌘ K | Link einfügen |
Ctrl + ` / ⌘ ` | Inline umschalten Code |
Ctrl + Shift + S / ⌘ ⇧ S | Schalten Sie |
Ctrl + 1 / ⌘ 1 | Überschrift 1 |
Ctrl + 2 / ⌘ 2 | Überschrift 2 |
Ctrl + 3 / ⌘ 3 | Überschrift 3 |
Ctrl + L / ⌘ L | Aufzählungsliste umschalten |
Ctrl + Z / ⌘ Z | Rückgängig machen |
Ctrl + Shift + Z / ⌘ ⇧ Z | Wiederholen |
Tab | Ausgewählte Zeilen einrücken |
Shift + Tab | Ausgewählte Zeilen ausrücken |
Ctrl + F / ⌘ F | Öffnen Sie das Suchfeld |
Ctrl + H / ⌘ H | Öffnen Sie das Bedienfeld „Suchen und Ersetzen“. |
Ctrl + Shift + F / ⌘ ⇧ F | Vollbildvorschau umschalten |
F11 | Vollbildvorschau umschalten |
Escape | Schließen Sie das Suchfeld/Vollbildvorschau beenden |
🔍 Suchen und Ersetzen
Im Editor ist ein integriertes Such- und Ersetzungsfeld verfügbar: Es ist keine Browsererweiterung oder ein separates Tool erforderlich.
- Drücken Sie
Ctrl + F(oder⌘ F), um das Bedienfeld Suchen zu öffnen - Drücken Sie
Ctrl + H(oder⌘ H), um das Bedienfeld Suchen und Ersetzen zu öffnen - Die Suche berücksichtigt Groß- und Kleinschreibung und zeigt einen Live-Match-Zähler an (z. B. 3 von 12)
- Navigieren Sie durch Übereinstimmungen mit den Tasten ▲ / ▼ oder
Enter/Shift + Enter - Ersetzen ersetzt die aktuell hervorgehobene Übereinstimmung; Alle ersetzen ersetzt jedes Vorkommen auf einmal
- Drücken Sie
Escapeum das Bedienfeld zu schließen und den Fokus wieder auf den Editor zu richten
Das Bedienfeld verschiebt sich in der oberen rechten Ecke des Editor-Inhaltsbereichs und unterbricht den Schreibvorgang nicht.
🔗 Links von einer eingefügten URL
Wählen Sie einen Text aus, fügen Sie eine URL darüber ein und Sie erhalten einen Markdown-Link anstelle der URL, die Ihre Auswahl ersetzt.
1 2 | Read the docs <- select "the docs", paste https://example.com Read [the docs](https://example.com) <- what you get |
Die Regel ist bewusst streng: nur ein Bare http oder https URLs ohne Leerzeichen werden auf diese Weise behandelt. Das Einfügen eines Satzes, der zufällig eine URL enthält, oder das Einfügen ohne Auswahl verhält sich wie ein gewöhnliches Einfügen.
Merkmale
🔌 Native Formularintegration
Funktioniert genau wie ein Standard <textarea>. Keine komplexen APIs: Verwenden Sie einfach die value oder name Attribut. Es „funktioniert einfach“ mit Standard-HTML-Formularübermittlungen in PHP, Django oder Node.js.
🖼️ Erweiterter Bild-Upload
Konfigurieren Sie native Server-Uploads über die API. Vermeiden Sie schwere Base64-Strings, um schnellere Seitenladevorgänge und eine bessere Suchmaschinenoptimierung zu gewährleisten, indem Sie Bilder auf Ihrem eigenen CDN hosten.
🔀 Hybrid- und Normalmodus
Wechseln Sie zwischen a Hybrid (WYSIWYG) Erfahrung in der visuellen Bearbeitung bzw Einfacher Abschlag Modus für ein traditionelles Codierungsgefühl.
🚀 Hohe Leistung
A 53 KB gezippt Bundle (252 KB minimiert, CSS enthalten), optimiert für „Heavy Content“. Verarbeitet umfangreiche Dokumente und große Dateien ohne Eingabeverzögerung oder Leistungseinbußen. Entprellte Vorschau-Updates, zwischengespeicherte Stilberechnungen und konfliktfreie Tastaturbedienung: Tab und Enter machen also immer genau das Gleiche.
🌍 Integrierte RTL-Unterstützung
Native Unterstützung für Rechts-nach-Links-Sprachen wie Arabisch, Urdu und Farsi. Perfekt für die Erstellung global zugänglicher Anwendungen.
✨ Syntaxhervorhebung
Verbesserte Lesbarkeit durch klaren Code und Markdown-Formatierung.
🌙 Adaptives Theming
Beinhaltet automatische Unterstützung für den Dunkelmodus. Es synchronisiert sich mit Ihren Systemeinstellungen oder dem Frutjam-Benutzeroberfläche Bibliothek für ein nahtloses visuelles Erlebnis.
📝 Intelligente Bearbeitung
Automatische Listenfortsetzung im GitHub-Stil für geordnete Listen, ungeordnete Listen und Checklisten: Drücken Sie Enter und der Editor setzt das Muster fort. Kontrollkästchen im Vorschaubereich sind anklickbar und werden sofort wieder mit der Markdown-Quelle synchronisiert.
📱 Vollständig reaktionsfähig
Eine flüssige, auf Mobilgeräte ausgerichtete Benutzeroberfläche, die sich für die Bearbeitung unterwegs perfekt an Desktops, Tablets und Smartphones anpasst.
📦 Universelle Unterstützung
Kompatibel mit ESM, UMD, CommonJS und IIFE. Funktioniert sofort über CDN (<script src>), npm oder ein beliebiger Bundler (Vite, Webpack, Rollup): keine zusätzliche Konfiguration erforderlich.
♿ Standardmäßig zugänglich
Vollständige ARIA-Unterstützung integriert: Wahrzeichen der Symbolleiste, beschrifteter Vorschaubereich, bildschirmleserfreundliche Schaltflächen, aria-pressed auf dem Vorschau-Schalter, disabled Und aria-disabled bei inaktiven Werkzeugen und korrekte Fokuswiederherstellung, wenn Modalitäten geschlossen werden.
🛡️ Keine CSS-Konflikte
Editor-Stile sind vollständig anwendbar .markdown-editor-wrapper. Der globale Preflight von Tailwind ist ausgeschlossen, sodass der Editor sicher neben Bootstrap, Tailwind oder einem anderen Framework leben kann, ohne deren Stile zu beeinträchtigen.
⌨️ Tastaturkürzel
Ctrl+B, Ctrl+I, Ctrl+K, Ctrl+`, Ctrl+Shift+S: gängige Formatierungsaktionen ohne Berühren der Maus. Jede Verknüpfung wird im Tooltip der Symbolleistenschaltfläche angezeigt.
🔍 Suchen und Ersetzen
Drücken Ctrl+F finden bzw Ctrl+H , um Suchen und Ersetzen zu öffnen. Suche ohne Berücksichtigung der Groß-/Kleinschreibung mit Live-Match-Zähler, Nächster/Vorheriger-Navigation, Einzelersetzen und Alle ersetzen: ohne den Editor zu verlassen.
🔒 XSS-sichere Vorschau
Die gerenderte Vorschau wird über bereinigt DOMPurify bevor es in das DOM geschrieben wird. Skript-Tags, Inline-Ereignishandler und schädliche URLs in manipulierten Markdown-Eingaben werden automatisch entfernt: Es ist keine Konfiguration erforderlich.
▶️ Echtzeitvorschau
Sehen Sie, wie Ihr Markdown während der Eingabe sofort gerendert wird.
🔗 Einfache Integration
Nahtlose Integration in jedes Webprojekt mit minimalem Setup.
🛠️ Anpassbare Symbolleiste
Konfigurieren Sie Symbolleistenoptionen wie Fettschrift, Kursivschrift usw. dynamisch und ordnen Sie sie neu an.
Vollständiges Konfigurationsbeispiel
Verwenden Sie dieses umfassende Beispiel, um MarkdownEditor mit allen Hauptfunktionen zu initialisieren, einschließlich der benutzerdefinierten Symbolleistenreihenfolge und der erweiterten Handhabung des Bild-Uploads.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | const editor = new MarkdownEditor('#markdown-editor', { mode: 'hybrid', placeholder: 'Start writing...', footer: { line: true, col: true, chars: true, words: true, }, onChange(value) { console.log('Content updated:', value.length, 'characters'); }, labels: { 'Bold': 'Gras', 'Italic': 'Italique', 'Uploading...': 'Téléversement...', }, toolbar: [ 'heading', 'bold', 'italic', 'strikethrough', 'blockquote', 'ul', 'ol', 'checklist', 'code', 'codeblock', 'hr', 'table', { image: { fileInput: { accept: ['webp', 'avif', 'png'], uploadUrl: '/api/upload' } } }, 'link', 'undo', 'redo', 'indent', 'outdent', 'preview' ], }); // Read content natively const markdown = document.getElementById('markdown-editor').value; // destroy() when the view unmounts (SPAs) // editor.destroy(); |
Fanden Sie das nützlich?
Ein GitHub-Stern hilft anderen Entwicklern, den Editor zu entdecken. Es ist Teil von Frutjam. Ein Stern dort hilft auch.