Pasek narzędzi, podgląd na żywo i WYSIWYG w obszarze tekstowym, który już posiadasz
Ostatnia aktualizacja:
Edytor przecen, który ulepsza obszar tekstowy zamiast go zastępować, dzięki czemu przesyłanie formularzy, sprawdzanie poprawności i wymagane pola nadal działają. WYSIWYG i zwykłe tryby Markdown, podgląd na żywo, znajdź i zamień, obsługa RTL, tryb ciemny. Działa samodzielnie z Django, Laravel, Rails, Node.js, PHP i dowolnym stosem.
Nie jest wymagany Frutjam ani Tailwind. Style są w pakiecie, więc edytor może włączyć się do dowolnego projektu.
Instalacja
NPM (bundlery: Vite, webpack, Rollup itp.)
npm install markdown-text-editor |
1 2 | import MarkdownEditor from 'markdown-text-editor'; new MarkdownEditor('#markdown-editor'); |
Definicje TypeScript są dostarczane z pakietem, więc opcje, wpisy na pasku narzędzi i zmienne kształty są sprawdzane i automatycznie uzupełniane bez dodatkowej instalacji.
CDN: moduł ES
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: globalny znacznik skryptu (IIFE)
Nie ma potrzeby importowania: MarkdownEditor jest automatycznie dostępny jako zmienna globalna.
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> |
Wersja demonstracyjna edytora Markdown
Szybki start
Przekaż obiekt opcji, aby dostosować edytor. Wszystkie opcje są opcjonalne: pomiń dowolną, aby użyć wartości domyślnej.
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'], }); |
Filozofia: „Najpierw rodzimy”
Większość redaktorów łamie standardowy przepływ pracy w sieci. MarkdownEditor to uwzględnia. Ponieważ znajduje się bezpośrednio na wierzchu <textarea>, nie musisz uczyć się nowego sposobu obsługi danych.
- Nie jest potrzebne wiązanie danych: Działa z
<form method="POST">po wyjęciu z pudełka - Dostęp standardowy: Użyj
document.getElementById('editor').valuetak jak normalne wejście. - Backend Agnostic: Działa z dowolnym backendem (Python, Node.js, PHP itp.), tak jak normalne pole formularza
MarkdownEditor kontra EasyMDE / SimpleMDE
Większość edytorów przecen JavaScript (EasyMDE, SimpleMDE, edytory oparte na CodeMirror) ukryj swoje <textarea> i edytuj kopię, zapisując treść ponownie po przesłaniu formularza. To działa, dopóki coś innego nie będzie potrzebowało tej wartości: a required pole, na którym przeglądarka nie może się skupić, całkowicie blokuje przesłanie, oraz .value Lub FormData read before Submit zwraca pusty ciąg znaków, który łamie zabezpieczenia htmx, Turbo, automatycznego zapisywania i niezapisanych zmian. MarkdownEditor jest inny. Stylizuje obszar tekstowy, który już posiadasz i pozostawia go jako pole, w którym piszesz, więc wartość jest zawsze poprawna.
| Funkcja | Edytor Markdown | EasyMDE / SimpleMDE |
|---|---|---|
| Zachowany natywny obszar tekstowy | ✅ | ❌ Ukryty, zredagowany jako kopia |
Współpracuje z required pola | ✅ | ❌ Przeglądarka blokuje przesyłanie |
.value popraw przed przesłaniem | ✅ | ❌ Puste do momentu wysłania formularza |
Serializuje z FormData, htmx, Turbo | ✅ | ❌ Wymaga własnego API edytora |
| Tryb hybrydowy WYSIWYG | ✅ | ❌ |
| Wbudowane narzędzie Znajdź i zamień | ✅ | ❌ |
| Wsparcie RTL | ✅ Wbudowany | Za pośrednictwem CodeMirror direction opcja |
| Wbudowane procedury obsługi zdarzeń (CSP) | ✅ Brak | Niektóre |
| Tryb ciemny / motyw | ✅ | Ograniczony |
| Rozmiar pakietu, zapinany na zamek | 53KB | 107 KB (JS + CSS) |
Integracja frameworków
Ponieważ MarkdownEditor zachowuje wersję natywną <textarea>integruje się z każdym frameworkiem backendowym bez dodatkowego kodu. Twój serwer otrzymuje treść przeceny dokładnie tak samo, jak z dowolnego standardowego pola formularza. W przypadku React i Vue potrzeba kilku linijek, które zostaną omówione na końcu tej sekcji.
Django
Dodaj class do widżetu obszaru tekstowego i zainicjuj edytor: request.POST['content'] działa bez dodatkowych kroków.
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
Używać f.text_area z klasą: $request->input('content') otrzymuje bezpośrednio przecenę.
1 2 | <textarea name="content" class="markdown-editor">{{ old('content') }}</textarea> <script>new MarkdownEditor('.markdown-editor');</script> |
Rubin na szynach
Współpracuje z form_with po wyjęciu z pudełka: params[:content] zawiera przecenę. W przypadku Turbo Drive użyj turbo:load zamiast 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 otrzymuje przecenę po przesłaniu formularza: brak kroku synchronizacji, brak niestandardowej ekstrakcji.
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'] działa dokładnie tak, jak każdy standardowy obszar tekstowy: upuść go, a obsługa istniejącego formularza nie będzie wymagała żadnych zmian.
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> |
Zareagować
Utwórz edytor w efekcie i zniszcz go po odmontowaniu. Używać defaultValue zamiast value: edytor zapisuje bezpośrednio w obszarze tekstowym, więc kontrolowane wiązanie zastąpiłoby to, co pisze użytkownik.
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} />; } |
Powracający editor.destroy() z efektu obejmuje również StrictMode, który uruchamia efekty dwukrotnie w fazie rozwoju i w przeciwnym razie pozostawiłby dwóch redaktorów w jednym obszarze tekstowym. Pusta tablica zależności jest zamierzona: opcje są odczytywane raz podczas tworzenia edytora, więc ponowne uruchomienie efektu spowodowałoby jego zniszczenie i odbudowanie przy każdej zmianie.
Vue
Ten sam pomysł. Po wprowadzeniu ustaw wartość początkową onMounted i nie wiązać :valuelub każde naciśnięcie klawisza emitowane z powrotem v-model nadpisałby obszar tekstowy.
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> |
Używany jako <MarkdownField v-model="content" />. W prostej formie możesz pominąć v-model całkowicie i przeczytaj wartość z pola tekstowego po przesłaniu, tak jak w przypadku każdego innego frameworka.
Konfiguracja
Możesz w pełni dostosować zachowanie i interfejs edytora, przekazując plik options obiekt. Jeśli pominiesz opcję, zostanie użyta wartość domyślna.
Opcje są odczytywane jednorazowo, podczas konstruowania edytora. Późniejsza ich zmiana nie ma żadnego efektu: zadzwoń destroy() i zamiast tego utwórz nowy edytor.
| Nieruchomość | Typ | Domyślny | Zamiar |
|---|---|---|---|
mode | string | 'plain' | Ustawia widok początkowy. Użyj hybrydy, aby uzyskać doświadczenie WYSIWYG lub zwykłej, aby uzyskać surową składnię. |
placeholder | string | 'Write...' | Tekst wyświetlany, gdy edytor jest pusty. |
toolbar | array | [...] | Określa, które narzędzia pojawiają się i w jakiej kolejności. |
footer | fałsz | obiekt | wszystko widoczne | Steruje paskiem stanu wyświetlanym pod edytorem. Zabierać się do pracy false aby całkowicie go ukryć, lub przekaż obiekt, aby przełączyć poszczególne statystyki. |
theme | string | inherited | Explicitly sets the editor theme (light, dark, snowberry, darkberry). Jeśli zostanie pominięty, redaktor dziedziczy data-theme od najbliższego elementu nadrzędnego lub <textarea> się. |
minHeight | number | 200 | Minimalna wysokość w pikselach, do której edytor się zmniejszy, gdy treść będzie krótka. W parze z maxHeight aby ustawić zakres automatycznego wzrostu. |
maxHeight | number | 500 | Maksymalna wysokość w pikselach, do jakiej może urosnąć edytor w trybie innym niż pełnoekranowy. Gdy treść przekroczy tę wysokość, w edytorze pojawi się pasek przewijania. Edytor posiada również uchwyt przeciągania, dzięki czemu użytkownicy mogą ręcznie zmieniać jego rozmiar powyżej tego limitu. |
renderer | function | marked | Zastępuje analizator przecen używany w podglądzie. Odbiera ciąg przeceny i musi zwrócić ciąg HTML. |
sanitizer | function | DOMPurify | Zastępuje narzędzie dezynfekujące HTML. Odbiera wyrenderowany kod HTML i musi zwrócić bezpieczny kod HTML do wyświetlenia. |
onChange | function | undefined | Wywołanie zwrotne uruchamiane przy każdej zmianie treści: pisaniu, akcjach na pasku narzędzi, cofaniu/ponawianiu i kontynuacji listy. Odbiera bieżący ciąg przeceny jako jedyny argument. |
labels | object | undefined | Tłumaczenia własnego interfejsu edytora, oznaczone angielskim ciągiem znaków. Wszystko, co pominiesz, pozostanie w języku angielskim. |
🛠 Dostosowywanie paska narzędzi
Pasek narzędzi jest modułowy. Modyfikując tablicę, możesz stworzyć minimalne środowisko lub w pełni funkcjonalny pakiet mocy.
Dostępne narzędzia
| Kategoria | Klucze narzędziowe |
|---|---|
| Typografia | heading, bold, italic, strikethrough, blockquote |
| Listy | ul (bullet), ol (numbered), checklist |
| Kod | code (w linii), codeblock (blok ogrodzony) |
| Wkładki | hr (reguła pozioma), table (szablon tabeli) |
| Głoska bezdźwięczna | link, image |
| Redagowanie | undo, redo, indent, outdent |
| Pogląd | preview |
| Szablony | { variables: [...] }, skonfigurowany inline |
Informacje o narzędziu
| Narzędzie | Opis |
|---|---|
heading | Otwiera menu rozwijane umożliwiające wybranie poziomu nagłówka H1–H6 |
bold | Włącza pogrubione formatowanie tekstu. |
italic | Umożliwia formatowanie tekstu kursywą. |
strikethrough | Umożliwia przekreślenie tekstu. |
ol | (Lista uporządkowana): Konwertuje tekst na format listy numerowanej. |
ul | (Lista nieuporządkowana): Konwertuje tekst na listę punktowaną. |
checklist | Dodaje pola wyboru do tekstu, dzięki czemu doskonale nadaje się do zadań, list rzeczy do zrobienia lub śledzenia stanu ukończenia. |
blockquote | Zaznacz cytowany lub podkreślony tekst. |
code | Zawija zaznaczony tekst pojedynczymi znacznikami dla kodu wbudowanego. Ponowne kliknięcie usuwa tylne znaczniki. |
codeblock | Zawija zaznaczony tekst w ogrodzonym bloku kodu z potrójnym znacznikiem. Ponowne kliknięcie usuwa ogrodzenia. |
hr | Wstawia A --- linia pozioma w pozycji kursora w osobnej linii. |
table | Wstawia startowy szablon tabeli przecen 2x3 w pozycji kursora. |
image | Umożliwia wstawianie obrazów za pomocą składni przecen. |
link | Umożliwia dodawanie hiperłączy do tekstu. |
undo | Aby cofnąć ostatnie zmiany. |
redo | Aby ponownie zastosować ostatnio cofnięte zmiany. |
indent | Aby zwiększyć poziom wcięcia. |
outdent | Aby zmniejszyć poziom wcięcia. |
preview | Przełącza pełnoekranowy podgląd obok siebie. Pola wyboru w panelu podglądu można kliknąć i natychmiast zaktualizować źródło przeceny. Naciśnij Escape, aby wyjść z trybu pełnoekranowego. Jeśli stały nagłówek zakrywa edytor w trybie pełnoekranowym, zobacz --mte-fullscreen-z-index. |
💡 Wskazówki dotyczące wdrożenia:
- Zmiana kolejności: Przyciski pojawiają się dokładnie w takiej kolejności, w jakiej zostały wymienione w tablicy
- Usuwanie: Po prostu pomiń dowolny klawisz (np
image) z tablicy, aby całkowicie wyłączyć tę funkcję dla użytkownika - Natywna rezerwa: Jeśli nie podasz pliku
placeholderw JS wtyczka automatycznie użyje plikuplaceholderatrybut z kodu HTML<textarea>
📊 Stopka (pasek stanu)
Stopka znajduje się poniżej edytora i pokazuje linię, kolumnę kursora, liczbę znaków dokumentu i opcjonalnie liczbę słów, wszystko aktualizowane w czasie rzeczywistym. Jest ona domyślnie widoczna i każdą statystykę można przełączać niezależnie.
| Klawisz | Typ | Domyślny | Opis |
|---|---|---|---|
line | boolean | true | Pokaż bieżący numer linii. |
col | boolean | true | Pokaż bieżący numer kolumny. |
chars | boolean | true | Pokaż całkowitą liczbę znaków. |
words | boolean | false | Pokaż całkowitą liczbę słów. Domyślnie wyłączone: ustawione na true włączyć. |
Przykłady użycia
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 } }); |
🔀 Tryby edycji
MarkdownEditor oferuje dwa różne sposoby pisania i formatowania treści. Możesz przełączać się między tradycyjnym widokiem skupionym na składni lub nowoczesnym, opartym na wizualizacjach.
plain(Domyślne): Czyste, wydajne środowisko Markdown, w którym składnia (np**bold**Lub# heading) jest widoczne. Idealny dla programistów i purystów Markdownhybrid: Funkcja inspirowana WYSIWYG, która renderuje formatowanie (pogrubienie, kursywa, nagłówki) w czasie rzeczywistym podczas pisania, zachowując jednocześnie podstawową strukturę Markdown.
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' }); |
Podgląd trybu hybrydowego i zwykłego:
Tryb hybrydowy
Formatowanie wizualne jest renderowane w czasie rzeczywistym podczas pisania.
Tryb zwykły (domyślny)
Koncentruje się na surowej składni Markdown, aby zapewnić lekkość.
🌙 Tematyka
MarkdownEditor automatycznie dziedziczy motyw z otaczającej strony: nie jest wymagana żadna konfiguracja. Redaktor czyta data-theme od najbliższego przodka podczas inicjalizacji, dzięki czemu pozostaje zsynchronizowany z motywem Twojej witryny od razu po wyjęciu z pudełka.
Sposób rozwiązania tematu (kolejność priorytetów)
themeopcja: jawne zastąpienie przekazane w obiekcie opcjidata-themena<textarea>: ustawiany bezpośrednio na elemenciedata-themena dowolnym przodku: np.<html>,<body>lub opakowanie<div>
Dostępne motywy
'light' (domyślny), 'dark', 'snowberry', 'darkberry'
Opcja 1, dziedzicz z <html> lub dowolny przodek (konfiguracja zerowa)
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> |
Opcja 2: ustaw data-theme bezpośrednio na <textarea>
1 2 3 4 | <textarea id="markdown-editor" data-theme="dark"></textarea> <script> new MarkdownEditor('#markdown-editor'); </script> |
Opcja 3: wyraźna theme opcja (zastępuje wszystko)
1 2 3 | new MarkdownEditor('#markdown-editor', { theme: 'dark' }); |
🎨 Motyw niestandardowy za pomocą zmiennych CSS
Możesz w pełni dostosować wygląd edytora, zastępując jego zmienne CSS w pliku .markdown-editor-wrapper element lub dowolny [data-theme] selektor. Wszystkie kolory korzystają z Przestrzeń barw OKLCH dla percepcyjnie jednolitych wyników.
| Zmienny | Zamiar | Światło domyślne | Ciemny domyślny |
|---|---|---|---|
--color-base | Tło redaktora | oklch(100% 0 0) | oklch(10.9% 0 0) |
--color-on-base | Podstawowy kolor tekstu | oklch(22% 0 0) | oklch(98% 0 0) |
--color-primary | Akcent podstawowy (aktywny pasek narzędzi, linki) | oklch(51.1% .262 277) | oklch(66.4% .184 286) |
--color-on-primary | Tekst na powierzchniach w kolorze podstawowym | oklch(96.2% .018 272) | oklch(10% .01 270) |
--color-secondary | Akcent wtórny | oklch(59.1% .293 323) | oklch(65% .18 220) |
--color-accent | Podświetl akcent (kod wbudowany, kursywa) | oklch(54.1% .281 293) | oklch(75% .18 50) |
--color-neutral | Powierzchnie neutralne (granice, przegrody) | oklch(15% 0 0) | oklch(85% 0 0) |
--color-error | Kolor stanu błędu | oklch(57.7% .245 27) | oklch(60% .22 30) |
--border-radius | Zaokrąglenie narożników ramki edytora | 0.25rem |
Przykład niestandardowego motywu
Zastąp dowolną zmienną on .markdown-editor-wrapper po zainicjowaniu edytora lub zdefiniuj niestandardowy [data-theme] blok w arkuszu stylów:
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' }); |
🌐 Język interfejsu
Tekst edytora, podpowiedzi, elementy menu, pola modalne i przyciski są domyślnie w języku angielskim. Przekaż labels obiekt, aby to przetłumaczyć. Klucze to angielskie ciągi znaków, tak działa gettext, więc podajesz tylko to, co chcesz zmienić, a wszystko, czego brakuje, wraca do angielskiego.
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...', }, }); |
Ma to największe znaczenie w przypadku treści zapisywanych od prawej do lewej. Języki arabski, urdu i perski układają się poprawnie, ale pasek narzędzi, na którym nadal widnieje napis „Pogrubiony” nad tekstem pisanym od prawej do lewej, jest przetłumaczony tylko w połowie.
🏷 Zmienne
Dodaje menu rozwijane paska narzędzi umożliwiające wstawianie symboli zastępczych. Przydatne, gdy osoba pisząca dokument nie jest programistą, który zdefiniował składnię symboli zastępczych, jak w przypadku szablonów wiadomości e-mail, faktur lub umów: wybiera czytelną nazwę i wstawia dla niej poprawną składnię.
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' ] }); |
Narzędzie jest konfigurowane bezpośrednio w pliku toolbar array, więc jego położenie wśród innych przycisków zależy od Ciebie. Przycisk wyświetla listę etykiet, a kliknięcie jednej z nich powoduje jej wstawienie value przy kursorze, zastępując dowolne zaznaczenie. Nic nie jest renderowane, jeśli lista jest pusta.
Przykładowe wartości w podglądzie
Wpis podany a sample pokazuje tę próbkę w podglądzie, podczas gdy obszar tekstowy zachowuje prawdziwy symbol zastępczy. Wpisy niezawierające jednego będą wyświetlane tak, jak zostały zapisane, więc możesz mieszać oba.
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}} |
Grupowanie
Daj wpis items zamiast A value aby wyrenderować sekcję nagłówkową. Wpisy grupowane i płaskie można mieszać na jednej liście.
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}}' } ]} ]} |
Rzeczy, które warto wiedzieć
- Edytor nigdy nie rozwiązuje zmiennych. Wstawia tekst, a Twoja aplikacja później zastępuje wartości rzeczywiste, zwykle po stronie serwera.
samplewpływa tylko na to, co wyświetla podgląd. - Etykiety są wyświetlane jako zwykły tekst, więc znaczniki na etykiecie nigdy nie są renderowane.
- Zniekształcone wpisy są pomijane zamiast wyrzucać, a przycisk w ogóle nie jest renderowany, gdy nie skonfigurowano niczego użytecznego.
🖋 Niestandardowy moduł renderujący
Podgląd jest renderowany za pomocą wyraźny i zdezynfekowany DOMPoczyść. Obydwa można wymienić. Użyj tej opcji, jeśli Twoja aplikacja już renderuje przeceny w innej bibliotece i chcesz, aby podgląd dokładnie odpowiadał produkcji.
Obie opcje są zwykłymi funkcjami, które pobierają ciąg znaków i zwracają ciąg znaków, więc każdy parser i każdy środek dezynfekujący będzie działać.
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 nadal działa na wyjściu, więc zachowujesz ochronę XSS bez konieczności konfigurowania czegokolwiek.
Niestandardowy środek dezynfekujący
Potrzebne tylko wtedy, gdy domyślnie usuwane są elementy emitowane przez moduł renderujący. DOMPurify usuwa <iframe> domyślnie, więc osadzanie wideo wymaga wyraźnej zgody. DOMPurify należy zaimportować we własnym kodzie, ponieważ kopia dołączona do edytora jest wewnętrzna.
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'] }) }); |
Używając znacznika skryptu zamiast pakietu pakującego, załaduj DOMPurify wraz z edytorem:
1 2 | <script src="https://cdn.jsdelivr.net/npm/dompurify"></script> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> |
Rzeczy, które warto wiedzieć
- Tylko podgląd. Formatowanie na żywo w trybie hybrydowym wykorzystuje oddzielny wewnętrzny moduł renderujący i nie ma na to wpływu.
- Listy zadań wymagają obsługi wtyczek. Klikalne pola wyboru można znaleźć, szukając
input[type="checkbox"]na wyjściu, więc przecena jest potrzebnamarkdown-it-task-lists. Edytor rejestruje ostrzeżenie, jeśli wykryje składnię listy zadań i brak pól wyboru. - Oba muszą być synchroniczne i zwracać ciąg znaków. Jakiś
asyncfunkcja pisze[object Promise]w podglądzie. - Wymiana środka dezynfekującego zastępuje ochronę. Przejście, np
html => htmlcałkowicie wyłącza odkażanie i jest bezpieczny tylko dla w pełni zaufanych treści.
🎨 Stylizacja elementów wewnętrznych
Zmienne CSS obejmują większość motywów, ponieważ dziedziczą, więc należy je włączyć .markdown-editor-wrapper dociera do paska narzędzi, przycisków, podglądu i stopki. Sięgaj po nazwę klasy tylko wtedy, gdy żadna zmienna nie ujawnia tego, czego potrzebujesz.
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); } |
Odniesienie do klasy
Nazwy tych klas są stabilne i bezpieczne w stylizowaniu.
| Klasa | Element |
|---|---|
.markdown-editor-wrapper | Zewnętrzny pojemnik owijający cały edytor |
.toolbar | Pasek narzędzi nad obszarem edycji |
.markdown-btn | Indywidualny przycisk paska narzędzi |
.preview-btn | Przycisk przełączania podglądu/pełnego ekranu |
.editor-layout | Siatka zawierająca obszar edycji i podgląd obok siebie |
.textarea-wrapper | Otok wokół obszaru edycji |
.editor-textarea | Podstawowy element pola tekstowego |
.display-layer | Wyrenderowana warstwa formatowania, tylko tryb hybrydowy |
.preview-wrapper | Kolumna podglądu |
.preview-content | Renderowana przecena w podglądzie |
.editor-footer | Pasek stanu poniżej edytora |
.find-replace-panel | Znajdź i zamień panel |
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); } |
Kierowanie na jednego redaktora
Jeśli na jednej stronie znajduje się kilku redaktorów, wybierz jednego z nich za pomocą data-editor. Opakowanie odzwierciedla jego identyfikator <textarea>, Więc <textarea id="notes"> daje ci [data-editor="notes"]. Sam identyfikator pozostaje w obszarze tekstowym, więc getElementById pracuje dalej.
1 2 3 4 | /* one editor only */ [data-editor="notes"] { --border-radius: 0; } |
🪟 Pełny ekran i warstwy (indeks Z)
W trybie pełnoekranowym edytor używa z-index: 10000, co usuwa warstwy, które większość frameworków interfejsu użytkownika rezerwuje dla stałych nagłówków i nakładek. Jeśli stały nagłówek lub pasek boczny nadal zakrywa edytor, zwiększ tę wartość.
Zastąp to za pomocą --mte-fullscreen-z-index. Wartość ma zastosowanie tylko w trybie pełnoekranowym i dziedziczy, więc ustawienie jej na dowolnym przodku obejmuje wszystkich edytorów znajdujących się pod nią.
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; } |
Interfejs API treści
Jedną z głównych zalet MarkdownEditor jest to, że utrzymuje bazę <textarea> doskonale zsynchronizowane. Niezależnie od tego, czy używasz nowoczesnego frameworku JavaScript, czy tradycyjnego backendu, takiego jak Django, PHP czy Laravel, przepływ pracy pozostaje prosty i natywny.
Czytanie i pisanie treści
1. Sposób rodzimy (zalecany)
Ponieważ edytor rozszerza standardowy obszar tekstowy, możesz używać znanych metod DOM. To najszybszy sposób na interakcję z danymi bez konieczności poznawania nowego API.
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. Używanie odniesienia do zmiennej
Jeśli masz odwołanie do elementu Textarea, możesz go użyć bezpośrednio: nie jest potrzebny żaden interfejs API specyficzny dla biblioteki.
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. Ustawianie początkowej zawartości po stronie serwera
Zalecany sposób ustawienia zawartości początkowej odbywa się bezpośrednio w pliku <textarea> HTML: działa to naturalnie z każdym frameworkiem backendowym (Django, Laravel, Rails, PHP itp.), a edytor renderuje go automatycznie podczas init.
1 2 | <!-- Recommended: set content server-side --> <textarea id="markdown-editor"># Hello World</textarea> |
Aby czytać lub aktualizować zawartość w czasie wykonywania, użyj wersji natywnej textarea wartość. Dzwonić editor.render() po aktualizacji w celu odświeżenia podglądu i warstwy hybrydowej.
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. Zburzenie edytora: destroy()
Dzwonić editor.destroy() aby usunąć opakowanie DOM edytora i przywrócić oryginał <textarea> do swojego miejsca w dokumencie. Przydatne w aplikacjach jednostronicowych podczas odmontowywania widoku.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor'); // Remove the editor and restore the plain textarea editor.destroy(); |
Reagowanie na zmiany za pomocą onChange
Przekaż onChange wywołanie zwrotne, aby otrzymywać powiadomienia o każdej zmianie treści. Odbiera bieżący ciąg przeceny.
1 2 3 4 5 | const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { console.log('Content changed:', value.length, 'characters'); } }); |
Wersja robocza automatycznego zapisywania za pomocą localStorage
Używać onChange aby zapisać wersję roboczą przy każdym naciśnięciu klawisza. Przywróć go, wypełniając obszar tekstowy przed inicjalizacją edytora.
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); }); |
Przesyłanie formularza
Ponieważ MarkdownEditor jest zbudowany bezpośrednio na wersji natywnej <textarea>, jest kompatybilny z każdym frameworkiem backendowym (Django, Laravel, PHP, Ruby on Rails itp.) od razu po wyjęciu z pudełka.
Tutaj błyszczy filozofia „Native-First”. Nie musisz ręcznie synchronizować danych przed przesłaniem formularza. Przeglądarka traktuje edytor dokładnie tak, jak standardowe pole wejściowe.
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> |
Notatka: Inicjalizacja wtyczki MarkdownEditor jest obowiązkowa
Po prostu użyj standardowego kodu HTML <form>. The name atrybut w obszarze tekstowym jest tym, czego Twój serwer użyje do identyfikacji treści.
🚀 Dlaczego to zmienia zasady gry dla backendów
Ponieważ redaktor zachowuje natywny <textarea> zachowanie, serwer obsługuje dane jako standardowy ciąg znaków. Nie jest wymagana żadna dodatkowa logika: nie preventDefault() i brak instrukcji FormData budowa.
💡 Dlaczego jest to „funkcja zabójcza”:
Większość edytorów (np. Quill, Editor.js, simpleMDE, easyMDE) zapisuje dane w złożonych strukturach JSON. Jeśli programista z nich korzysta, musi przepisać schemat bazy danych i logikę renderowania.
Dzięki MarkdownEditor programista może zastąpić starą witrynę zwykłą <textarea> z edytorem, a backend nawet nie wie, że to się zmieniło. Po prostu otrzymuje ten sam surowy tekst, co zawsze, ale użytkownik otrzymuje 10 razy lepsze wrażenia.
| Ramy / język | Jak uzyskać dostęp do treści Markdown |
|---|---|
| PHP | $_POST['content'] |
| Django | request.POST.get('content') |
| Node.js (ekspresowy) | req.body.content |
| Laravel | $request->input('content') |
| Rubin na szynach | params[:content] |
🖼️ Zaawansowane przesyłanie obrazu
Natywna obsługa przesyłania obrazów: zamiast polegać na powolnych, obciążających pamięć ciągach Base64, jest to znacząca korzyść zarówno pod względem wydajności, jak i SEO.
Wklej i upuść
Wklej zrzut ekranu lub przeciągnij plik obrazu do edytora, a zostanie on przesłany przez ten sam punkt końcowy, co przycisk paska narzędzi. Symbol zastępczy pojawia się natychmiast, dzięki czemu edytor nigdy nie wygląda na zamrożony, a po przesłaniu zostaje zastąpiony prawdziwą ścieżką. Jeśli przesyłanie nie powiedzie się, symbol zastępczy zostanie zastąpiony widocznym znacznikiem, a nie znika po cichu.
To wymaga uploadUrl skonfigurowany poniżej. Bez tego wklejenie obrazu nic nie da, a edytor zarejestruje ostrzeżenie wyjaśniające, co dodać, ponieważ alternatywą byłby ciąg znaków Base64 w Twojej bazie danych.
Przesyłanych jest kilka plików na raz, więc obrazy lądują w kolejności, w jakiej przybyły.
Opcje konfiguracji
Narzędzie obrazu obsługuje a fileInput konfiguracja do obsługi bezpośredniego przesyłania na serwer.
accept: zdefiniuj tablicę dozwolonych formatów obrazów (np. „webp”, „avif”)uploadUrl: Określ punkt końcowy zaplecza, w którym plikFileobiekt zostanie przesłany za pośrednictwemPOSTparams: Opcjonalny obiekt do wysyłania dodatkowych danych (takich jak tokeny CSRF, identyfikatory użytkowników lub nazwy folderów) wraz z plikiem obrazu
Przykład użycia (pełna konfiguracja)
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); |
📡 Integracja serwerów
Żądanie
Redakcja przesyła POST żądanie jako multipart/form-data. Domyślnie zawiera:
image_file: Rzeczywisty obiekt plikuimage_alt: Tekst alternatywny wprowadzony przez użytkownika- ...plus wszelkie niestandardowe dane zdefiniowane w pliku
paramsobiekt
Wymagana odpowiedź
Aby potwierdzić pomyślne przesłanie i wstawić obraz do edytora, Twój serwer musi zwrócić następującą strukturę JSON:
1 2 3 4 | { "success": true, "image_path": "https://cdn.yourdomain.com/uploads/image.webp" } |
Uwaga: Upewnij się, że używasz klucza image_path dla adresu URL przesłanego obrazu.
Walidacja tekstu alternatywnego obrazu (altInput)
Aby mieć pewność, że Twoje treści pozostaną dostępne i przyjazne dla SEO, MarkdownEditor domyślnie wymusza sprawdzanie poprawności tekstu alternatywnego.
- Zachowanie domyślne: Jeśli
altInputnie jest zdefiniowany, domyślnie jest to{ required: true } - Wymuś dostępność: Użytkownicy nie będą mogli wstawić obrazu, dopóki nie zostanie podany opis alternatywny
1. Domyślne (nie wymaga konfiguracji)
1 2 3 4 | // Alt text is REQUIRED by default image: { fileInput: { uploadUrl: '/api/upload' } } |
2. Skrót (wyłącz weryfikację)
Jeśli chcesz zezwolić na obrazy bez opisów, po prostu ustaw wartość logiczną na false.
1 2 3 | image: { altInput: false // Users can now skip the alt text field } |
3. Oparte na obiektach (jawne)
1 2 3 4 5 | image: { altInput: { required: false // Disables alt text validation — users can skip the alt field } } |
Standardowe użycie obrazu (nie fileInput)
Jeśli fileInput nie jest skonfigurowany, edytor domyślnie korzysta z prostego modalu opartego na adresie URL. Jest to idealne rozwiązanie, jeśli Twoi użytkownicy głównie łączą się z zewnętrznymi hostami obrazów.
1 2 3 4 5 6 7 8 | const options = { toolbar: [ 'link', 'image', 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
💡 Po co używać parametrów?
W frameworkach takich jak Laravel czy Django nie można przesyłać plików bez tokena CSRF. Dodając _token do params obiekt, Twoje żądanie bezproblemowo przejdzie przez oprogramowanie pośredniczące zabezpieczające zaplecza, zachowując filozofię „Zero Logic” dla kontrolerów po stronie serwera.
⌨️ Skróty klawiaturowe
Typowe czynności formatowania można uruchomić bezpośrednio z klawiatury, bez dotykania paska narzędzi. Każdy skrót jest także pokazany w podpowiedzi odpowiedniego przycisku na pasku narzędzi.
| Skrót | Działanie |
|---|---|
Ctrl + B / ⌘ B | Przełącz Pogrubienie |
Ctrl + I / ⌘ I | Przełącz kursywa |
Ctrl + K / ⌘ K | Wstaw link |
Ctrl + ` / ⌘ ` | Przełącz w tekście Code |
Ctrl + Shift + S / ⌘ ⇧ S | Przełącz |
Ctrl + 1 / ⌘ 1 | Nagłówek 1 |
Ctrl + 2 / ⌘ 2 | Nagłówek 2 |
Ctrl + 3 / ⌘ 3 | Nagłówek 3 |
Ctrl + L / ⌘ L | Przełącz listę punktowaną |
Ctrl + Z / ⌘ Z | Anulować |
Ctrl + Shift + Z / ⌘ ⇧ Z | Przerobić |
Tab | Wcięcie wybranych linii |
Shift + Tab | Zmniejsz wybrane linie |
Ctrl + F / ⌘ F | Otwórz panel Znajdź |
Ctrl + H / ⌘ H | Otwórz panel Znajdź i zamień |
Ctrl + Shift + F / ⌘ ⇧ F | Przełącz podgląd pełnoekranowy |
F11 | Przełącz podgląd pełnoekranowy |
Escape | Zamknij panel Znajdź / Wyjdź z podglądu pełnoekranowego |
🔍 Znajdź i zamień
W edytorze dostępny jest wbudowany panel wyszukiwania i zamiany: nie jest potrzebne żadne rozszerzenie przeglądarki ani osobne narzędzie.
- Naciskać
Ctrl + F(Lub⌘ F), aby otworzyć panel Znajdź - Naciskać
Ctrl + H(Lub⌘ H), aby otworzyć panel Znajdź i zamień - Wyszukiwanie nie uwzględnia wielkości liter i wyświetla licznik meczów na żywo (np. 3 z 12)
- Nawiguj po meczach za pomocą przycisków ▲ / ▼ lub
Enter/Shift + Enter - Zamień zastępuje aktualnie podświetlone dopasowanie; Opcja Zamień wszystko powoduje jednoczesne zastąpienie wszystkich wystąpień
- Naciskać
Escapeaby zamknąć panel i powrócić do edytora
Panel unosi się w prawym górnym rogu obszaru zawartości edytora i nie zakłóca pisania.
🔗 Linki z wklejonego adresu URL
Wybierz jakiś tekst, wklej nad nim adres URL, a zamiast adresu URL zastąpisz wybrany link, otrzymasz link przecenowy.
1 2 | Read the docs <- select "the docs", paste https://example.com Read [the docs](https://example.com) <- what you get |
Zasada jest celowo surowa: tylko naga http Lub https Adres URL bez białych znaków jest traktowany w ten sposób. Wklejenie zdania zawierającego adres URL lub wklejenie bez zaznaczenia zachowuje się jak zwykłe wklejanie.
Cechy
🔌 Integracja formularzy natywnych
Działa dokładnie jak standard <textarea>. Żadnych skomplikowanych interfejsów API: po prostu użyj value Lub name atrybut. To „po prostu działa” ze standardowymi formularzami HTML w PHP, Django lub Node.js.
🖼️ Zaawansowane przesyłanie obrazu
Skonfiguruj przesyłanie natywnego serwera za pośrednictwem interfejsu API. Unikaj ciężkich ciągów Base64, aby zapewnić szybsze ładowanie strony i lepsze SEO, hostując obrazy we własnej sieci CDN.
🔀 Tryby hybrydowe i zwykłe
Przełącz między Hybrydowy (WYSIWYG) doświadczenie w edycji wizualnej lub Zwykły Markdown tryb zapewniający tradycyjne wrażenia z kodowania.
🚀 Wysoka wydajność
A 53 KB spakowane w formacie gzip pakiet (zminimalizowany 252 KB, zawiera CSS) zoptymalizowany pod kątem „Ciężkich treści”. Obsługuje ogromne dokumenty i duże pliki bez opóźnień wejściowych i spadków wydajności. Odrzucone aktualizacje podglądu, obliczenia stylu w pamięci podręcznej i bezkonfliktowa obsługa klawiatury: więc Tab i Enter zawsze robią dokładnie jedną rzecz.
🌍 Wbudowana obsługa RTL
Natywna obsługa języków pisanych od prawej do lewej, takich jak arabski, urdu i perski. Idealny do tworzenia aplikacji dostępnych na całym świecie.
✨ Podświetlanie składni
Zwiększona czytelność dzięki przejrzystemu kodowi i formatowaniu przecen.
🌙 Motywy adaptacyjne
Zawiera automatyczną obsługę trybu ciemnego. Synchronizuje się z ustawieniami systemu lub Interfejs użytkownika Frutjama biblioteka zapewniająca płynne wrażenia wizualne.
📝 Inteligentna edycja
Automatyczna kontynuacja list w stylu GitHuba dla list uporządkowanych, list nieuporządkowanych i list kontrolnych: naciśnij Enter a redaktor kontynuuje wzór. Pola wyboru w okienku podglądu można kliknąć i natychmiast synchronizować ze źródłem przecen.
📱 W pełni responsywny
Płynny, dostosowany do urządzeń mobilnych interfejs użytkownika, który idealnie dopasowuje się do komputerów stacjonarnych, tabletów i smartfonów, umożliwiając edycję w dowolnym miejscu.
📦 Uniwersalne wsparcie
Kompatybilny z ESM, UMD, CommonJS i IIFE. Działa od razu po wyjęciu z pudełka przez CDN (<script src>), npm lub dowolny pakiet (Vite, webpack, Rollup): nie jest wymagana dodatkowa konfiguracja.
♿ Dostępne domyślnie
Wbudowana pełna obsługa ARIA: punkt orientacyjny na pasku narzędzi, oznaczony obszar podglądu, przyciski przyjazne dla czytnika ekranu, aria-pressed na przełączniku podglądu, disabled I aria-disabled na nieaktywnych narzędziach i prawidłowe przywracanie ostrości po zamknięciu modułów.
🛡️ Zero konfliktów CSS
Style edytora są w pełni dostępne .markdown-editor-wrapper. Globalna inspekcja wstępna Tailwinda jest wykluczona, więc edytor może bezpiecznie współpracować z Bootstrapem, Tailwindem lub jakimkolwiek innym frameworkiem, nie naruszając ich stylu.
⌨️ Skróty klawiaturowe
Ctrl+B, Ctrl+I, Ctrl+K, Ctrl+`, Ctrl+Shift+S: typowe czynności formatowania bez dotykania myszy. Każdy skrót jest pokazany w etykiecie przycisku paska narzędzi.
🔍 Znajdź i zamień
Naciskać Ctrl+F znaleźć lub Ctrl+H aby otworzyć opcję Znajdź i zamień. Wyszukiwanie bez rozróżniania wielkości liter z licznikiem dopasowań na żywo, nawigacją następny/poprzedni, pojedynczą zamianą i zamianą wszystkich: bez opuszczania edytora.
🔒 Podgląd bezpiecznego XSS
Wyrenderowany podgląd jest oczyszczany poprzez DOMPoczyść przed zapisaniem w DOM. Tagi skryptów, wbudowane procedury obsługi zdarzeń i złośliwe adresy URL w spreparowanych danych wejściowych Markdown są usuwane automatycznie: nie jest wymagana żadna konfiguracja.
▶️ Podgląd w czasie rzeczywistym
Zobacz, jak Twoje przeceny są renderowane natychmiastowo podczas pisania.
🔗 Łatwa integracja
Bezproblemowo integruj się z dowolnym projektem internetowym przy minimalnej konfiguracji.
🛠️ Konfigurowalny pasek narzędzi
Dynamicznie konfiguruj i zmieniaj kolejność opcji paska narzędzi, takich jak pogrubienie, kursywa i inne.
Przykład pełnej konfiguracji
Użyj tego obszernego przykładu, aby zainicjować MarkdownEditor ze wszystkimi podstawowymi funkcjami, w tym niestandardową kolejnością pasków narzędzi i zaawansowaną obsługą przesyłania obrazów.
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(); |
Uznałeś to za przydatne?
Gwiazda GitHuba pomaga innym programistom odkryć edytor. To część Frutjam. Gwiazdka też pomaga.