Skip to main content

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.)

bash
npm install markdown-text-editor
javascript
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

html
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.

html
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.

javascript
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').value tak 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.

FunkcjaEdytor MarkdownEasyMDE / 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✅ WbudowanyZa pośrednictwem CodeMirror direction opcja
Wbudowane procedury obsługi zdarzeń (CSP)✅ BrakNiektóre
Tryb ciemny / motyw✅Ograniczony
Rozmiar pakietu, zapinany na zamek53KB107 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.

python
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'}),
        }
javascript
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ę.

html
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.

javascript
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.

html
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.

html
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.

javascript
 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 &lt;textarea ref={ref} name={name} defaultValue={defaultValue} /&gt;;
}

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.

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
&lt;script setup&gt;
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 =&gt; emit('update:modelValue', value)
    });
});

onBeforeUnmount(() =&gt; editor?.destroy());
&lt;/script&gt;

&lt;template&gt;&lt;textarea ref="el"&gt;&lt;/textarea&gt;&lt;/template&gt;

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śćTypDomyślnyZamiar
modestring'plain'Ustawia widok początkowy. Użyj hybrydy, aby uzyskać doświadczenie WYSIWYG lub zwykłej, aby uzyskać surową składnię.
placeholderstring'Write...'Tekst wyświetlany, gdy edytor jest pusty.
toolbararray[...]Określa, które narzędzia pojawiają się i w jakiej kolejności.
footerfałsz | obiektwszystko widoczneSteruje 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.
themestringinheritedExplicitly 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ę.
minHeightnumber200Minimalna wysokość w pikselach, do której edytor się zmniejszy, gdy treść będzie krótka. W parze z maxHeight aby ustawić zakres automatycznego wzrostu.
maxHeightnumber500Maksymalna 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.
rendererfunctionmarkedZastępuje analizator przecen używany w podglądzie. Odbiera ciąg przeceny i musi zwrócić ciąg HTML.
sanitizerfunctionDOMPurifyZastępuje narzędzie dezynfekujące HTML. Odbiera wyrenderowany kod HTML i musi zwrócić bezpieczny kod HTML do wyświetlenia.
onChangefunctionundefinedWywoł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.
labelsobjectundefinedTł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

KategoriaKlucze narzędziowe
Typografiaheading, bold, italic, strikethrough, blockquote
Listyul (bullet), ol (numbered), checklist
Kodcode (w linii), codeblock (blok ogrodzony)
Wkładkihr (reguła pozioma), table (szablon tabeli)
Głoska bezdźwięcznalink, image
Redagowanieundo, redo, indent, outdent
Poglądpreview
Szablony{ variables: [...] }, skonfigurowany inline

Informacje o narzędziu

NarzędzieOpis
headingOtwiera menu rozwijane umożliwiające wybranie poziomu nagłówka H1–H6
boldWłącza pogrubione formatowanie tekstu.
italicUmożliwia formatowanie tekstu kursywą.
strikethroughUmożliwia przekreślenie tekstu.
ol(Lista uporządkowana): Konwertuje tekst na format listy numerowanej.
ul(Lista nieuporządkowana): Konwertuje tekst na listę punktowaną.
checklistDodaje pola wyboru do tekstu, dzięki czemu doskonale nadaje się do zadań, list rzeczy do zrobienia lub śledzenia stanu ukończenia.
blockquoteZaznacz cytowany lub podkreślony tekst.
codeZawija zaznaczony tekst pojedynczymi znacznikami dla kodu wbudowanego. Ponowne kliknięcie usuwa tylne znaczniki.
codeblockZawija zaznaczony tekst w ogrodzonym bloku kodu z potrójnym znacznikiem. Ponowne kliknięcie usuwa ogrodzenia.
hrWstawia A --- linia pozioma w pozycji kursora w osobnej linii.
tableWstawia startowy szablon tabeli przecen 2x3 w pozycji kursora.
imageUmożliwia wstawianie obrazów za pomocą składni przecen.
linkUmożliwia dodawanie hiperłączy do tekstu.
undoAby cofnąć ostatnie zmiany.
redoAby ponownie zastosować ostatnio cofnięte zmiany.
indentAby zwiększyć poziom wcięcia.
outdentAby zmniejszyć poziom wcięcia.
previewPrzełą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 placeholder w JS wtyczka automatycznie użyje pliku placeholder atrybut 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.

KlawiszTypDomyślnyOpis
linebooleantruePokaż bieżący numer linii.
colbooleantruePokaż bieżący numer kolumny.
charsbooleantruePokaż całkowitą liczbę znaków.
wordsbooleanfalsePokaż całkowitą liczbę słów. Domyślnie wyłączone: ustawione na true włączyć.

Przykłady użycia

javascript
 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 Markdown
  • hybrid: Funkcja inspirowana WYSIWYG, która renderuje formatowanie (pogrubienie, kursywa, nagłówki) w czasie rzeczywistym podczas pisania, zachowując jednocześnie podstawową strukturę Markdown.
javascript
 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)

  1. theme opcja: jawne zastąpienie przekazane w obiekcie opcji
  2. data-theme na <textarea>: ustawiany bezpośrednio na elemencie
  3. data-theme na 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)
html
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>
html
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)
javascript
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.

ZmiennyZamiarŚwiatło domyślneCiemny domyślny
--color-baseTło redaktoraoklch(100% 0 0)oklch(10.9% 0 0)
--color-on-basePodstawowy kolor tekstuoklch(22% 0 0)oklch(98% 0 0)
--color-primaryAkcent podstawowy (aktywny pasek narzędzi, linki)oklch(51.1% .262 277)oklch(66.4% .184 286)
--color-on-primaryTekst na powierzchniach w kolorze podstawowymoklch(96.2% .018 272)oklch(10% .01 270)
--color-secondaryAkcent wtórnyoklch(59.1% .293 323)oklch(65% .18 220)
--color-accentPodświetl akcent (kod wbudowany, kursywa)oklch(54.1% .281 293)oklch(75% .18 50)
--color-neutralPowierzchnie neutralne (granice, przegrody)oklch(15% 0 0)oklch(85% 0 0)
--color-errorKolor stanu błęduoklch(57.7% .245 27)oklch(60% .22 30)
--border-radiusZaokrąglenie narożników ramki edytora0.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:

css
 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;
}
javascript
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.

javascript
 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ę.

javascript
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.

javascript
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.

javascript
 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. sample wpł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ć.

javascript
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.

javascript
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:

html
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 potrzebna markdown-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ś async funkcja pisze [object Promise] w podglądzie.
  • Wymiana środka dezynfekującego zastępuje ochronę. Przejście, np html => html cał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.

css
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.

KlasaElement
.markdown-editor-wrapperZewnętrzny pojemnik owijający cały edytor
.toolbarPasek narzędzi nad obszarem edycji
.markdown-btnIndywidualny przycisk paska narzędzi
.preview-btnPrzycisk przełączania podglądu/pełnego ekranu
.editor-layoutSiatka zawierająca obszar edycji i podgląd obok siebie
.textarea-wrapperOtok wokół obszaru edycji
.editor-textareaPodstawowy element pola tekstowego
.display-layerWyrenderowana warstwa formatowania, tylko tryb hybrydowy
.preview-wrapperKolumna podglądu
.preview-contentRenderowana przecena w podglądzie
.editor-footerPasek stanu poniżej edytora
.find-replace-panelZnajdź i zamień panel
css
 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.

css
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ą.

css
 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.

javascript
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.

javascript
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.

html
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.

javascript
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.

javascript
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.

javascript
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.

javascript
 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.

html
 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ęzykJak uzyskać dostęp do treści Markdown
PHP$_POST['content']
Djangorequest.POST.get('content')
Node.js (ekspresowy)req.body.content
Laravel$request->input('content')
Rubin na szynachparams[: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 plik File obiekt zostanie przesłany za pośrednictwem POST
  • params: 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)

javascript
 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 pliku
  • image_alt: Tekst alternatywny wprowadzony przez użytkownika
  • ...plus wszelkie niestandardowe dane zdefiniowane w pliku params obiekt

Wymagana odpowiedź

Aby potwierdzić pomyślne przesłanie i wstawić obraz do edytora, Twój serwer musi zwrócić następującą strukturę JSON:

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 altInput nie 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)

javascript
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.

javascript
1
2
3
image: {
  altInput: false // Users can now skip the alt text field
}

3. Oparte na obiektach (jawne)

javascript
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.

javascript
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ótDziałanie
Ctrl + B  /  ⌘ BPrzełącz Pogrubienie
Ctrl + I  /  ⌘ IPrzełącz kursywa
Ctrl + K  /  ⌘ KWstaw link
Ctrl + `  /  ⌘ `Przełącz w tekście Code
Ctrl + Shift + S  /  ⌘ ⇧ SPrzełącz Przekreślenie
Ctrl + 1  /  ⌘ 1Nagłówek 1
Ctrl + 2  /  ⌘ 2Nagłówek 2
Ctrl + 3  /  ⌘ 3Nagłówek 3
Ctrl + L  /  ⌘ LPrzełącz listę punktowaną
Ctrl + Z  /  ⌘ ZAnulować
Ctrl + Shift + Z  /  ⌘ ⇧ ZPrzerobić
TabWcięcie wybranych linii
Shift + TabZmniejsz wybrane linie
Ctrl + F  /  ⌘ FOtwórz panel Znajdź
Ctrl + H  /  ⌘ HOtwórz panel Znajdź i zamień
Ctrl + Shift + F  /  ⌘ ⇧ FPrzełącz podgląd pełnoekranowy
F11Przełącz podgląd pełnoekranowy
EscapeZamknij 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ć Escape aby 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.

markdown
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.

javascript
 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.

Gwiazda na GitHubie
Edit page

Ostatnia aktualizacja: