Введение
Vditor — это редактор Markdown на стороне браузера. Он поддерживает WYSIWYG, мгновенное отображение (аналогично Typora) и режим предварительного просмотра с разделённым экраном. Vditor реализован на TypeScript и поддерживает нативный JavaScript и такие фреймворки, как Vue, React, Angular и Svelte.
Добро пожаловать на официальный сайт Vditor по адресу https://b3log.org/vditor, чтобы узнать больше.
Предыстория
С популяризацией методов набора текста в Markdown всё больше приложений начинают интегрировать редактор Markdown. Текущее состояние основных интегрируемых редакторов Markdown выглядит следующим образом:
Эти три пункта соответствуют трём сценариям применения:
Поэтому необходим редактор Markdown, который может адаптироваться к сценариям использования. Необходимо учитывать:
Vditor приложил усилия в этих областях, надеясь внести некоторый вклад в современную общую область редактирования Markdown.
Особенности
Поддержка трёх режимов редактирования: WYSIWYG (wysiwyg), мгновенный рендеринг (ir) и разделенный вид (sv).
Поддержка структуры, математических формул, mind-карт. Карты, диаграммы, блок-схемы, графики Ганта, временные шкалы, штатное расписание, мультимедиа, голосовое чтение, якорные заголовки, выделение и копирование кода, рендеринг Graphviz.
Встроенный механизм фильтрации безопасности, экспорт, отложенная загрузка изображений, список задач, мультиплатформенный предварительный просмотр, переключение между несколькими темами, функция копирования в WeChat/Zhihu.
Реализация спецификаций CommonMark и GFM, форматирование и просмотр синтаксического дерева Markdown, поддержка более 10 конфигураций.
Панель инструментов содержит более 36 операций. Помимо поддержки расширения, можно настроить сочетания клавиш, всплывающие подсказки, позиции подсказок, значки, события кликов, имена классов и вспомогательные панели инструментов.
Расширение автозаполнения для эмодзи/@/# и т. д.
Можно использовать перетаскивание, вставку и загрузку, отображать прогресс загрузки в реальном времени, поддерживать междоменную загрузку CORS.
Сохранять контент в режиме реального времени для предотвращения случайной потери данных.
Поддержка записи, пользователи могут напрямую публиковать голосовые сообщения.
Если вставка содержит изображения внешних ссылок, разметка HTML автоматически преобразуется в Markdown и может быть загружена на сервер через указанный интерфейс.
Поддерживается изменение размера главного окна с помощью перетаскивания, подсчёт символов.
Многотемный режим, встроенные чёрная, белая и зелёная темы.
Мультиязычная поддержка, встроенная локализация китайского, английского и корейского языков.
Поддержка основных браузеров, адаптирован для мобильных устройств.
🔮 Режимы редактирования
WYSIWYG — этот режим более удобен для пользователей, которые не знакомы с Markdown, и вы можете использовать его без проблем, если знакомы с Markdown.
Instant Rendering — этот режим должен быть знаком пользователям, знакомым с Typora. Теоретически это самый элегантный способ редактирования Markdown.
Split View — традиционный режим Split View подходит для редактирования Markdown на большом экране.
🍱 Синтаксическая поддержка
Поддерживаются все синтаксические конструкции CommonMark: тематические разрывы, заголовки ATX, заголовки Setext, блоки кода с отступом, блоки кода в фигурных скобках, HTML-блоки, определения ссылок на ссылки, абзацы, блочные цитаты, списки, обратные слэши, сущности и числовые символьные ссылки, кодовые интервалы, акценты и сильные акценты, ссылки, изображения, необработанный HTML, жёсткие и мягкие переносы строк, текстовое содержимое.
Также поддерживаются все конструкции GFM: таблицы, элементы списка задач, зачёркивание, автоссылки, фильтрация XSS.
Кроме того, поддерживается расширенный синтаксис Markdown: сноски, оглавление, пользовательские идентификаторы заголовков.
Синтаксис диаграмм:
Stave: поддерживается abc.js.
Математические формулы: блоки математических формул, математические формулы на уровне строк поддерживаются MathJax и KaTeX.
YAML Front Matter.
Оптимизация китайского контекста:
Большинство вышеперечисленных функций можно включить или отключить с помощью конфигурации переключателя, разработчики могут выбрать их в соответствии со своими сценариями применения.
🗃 Примеры использования
Sym — современная платформа сообщества (форум/BBS/SNS/блог), реализованная на Java. Solo и Pipe — B3log, распределённый узел блога сообщества, присоединяйтесь к сети сообществ следующего поколения. Arya — онлайн-редактор Markdown, основанный на Vue, Vditor. Больше примеров.
🛠️ User Guide
npm install vditor --save
import Vditor from 'vditor'
import "~vditor/src/assets/less/index" // Or use dark
const vditor = new Vditor(id, {options...})
<!-- ⚠️Please specify the version number in the production environment, such as https://cdn.jsdelivr.net/npm/vditor@x.x.x/dist... -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vditor/dist/index.css" />
<script src="https://cdn.jsdelivr.net/npm/vditor/dist/index.min.js"></script>
class="vditor-reset"
(классическая тема) или class="vditor-reset vditor-reset--dark"
(чёрная тема) в элемент отображения содержимого может сделать отображение содержимого более удобнымМожет быть заполнен элементом id
или самим элементом HTMLElement
⚠️: При заполнении элемента HTMLElement
, вам нужно установить options.cache.id
или установить options.cache.enable
в false
Объяснение | По умолчанию | |
---|---|---|
i18n | I18n, подробнее см. ITips | - |
undoDelay | Интервал отмены | - |
after | Метод обратного вызова после асинхронного рендеринга редактора завершён | - |
height | Общая высота редактора | 'auto' |
minHeight | Минимальная высота области редактирования | - |
width | Общая ширина редактора, поддерживает % | 'auto' |
placeholder | Советы, когда область ввода пуста | '' |
lang | Тип I18n: en_US, ja_JP, ko_KR, ru_RU, zh_CN, zh_TW | 'zh_CN' |
input | Триггер после ввода (значение: строка) | - |
focus | Триггер после фокусировки (значение: строка) | - |
blur | Триггер после потери фокуса (значение: строка) | - |
esc | Триггер после нажатия esc (значение: строка) | - |
ctrlEnter | Триггер после нажатия ⌘/ctrl+enter (значение: строка) | - |
select | Срабатывает после выбора текста в редакторе (значение: строка) | - |
tab | Операция с клавишей tab, поддержка \ t и любой строки |
- |
typewriterMode | Включить ли режим машинистки | false |
cdn | Настроить адрес собственной CDN | https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION} |
mode | Режим редактирования: sv, ir, wysiwyg | 'ir' |
debugger | Отображать ли журнал | false |
value | Значение инициализации редактора | '' |
theme | Тема: classic, dark | 'classic' |
icon | Тема иконки: ant, material | 'ant' |
toolbar: ['emoji', 'br', 'bold', '|', 'line']
. См. по умолчанию src/ts/util/Options.ts
emoji
, headings
, bold
, italic
, strike
, |
, line
, quote
, list
, ordered-list
, check
,outdent
,indent
, code
, inline-code
, insert-after
, insert-before
, code-theme
, content-theme
, export
, undo
, redo
, upload
, link
, table
, record
, edit-mode
, both
, preview
, fullscreen
, outline
, devtools
, info
, help
, br
name
не входит в перечисление, вы можете добавить пользовательскую кнопку в следующем формате:new Vditor('vditor', {
toolbar: [
{
hotkey: '⇧⌘S',
name: 'sponsor',
tipPosition: 's',
tip: '成为赞助者',
className: ```
{
"right",
icon: '<svg t="1589994565028" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2808" width="32" height="32"><path d="M506.6 423.6m-29.8 0a29.8 29.8 0 1 0 59.6 0 29.8 29.8 0 1 0-59.6 0Z" fill="#0F0F0F" p-id="2809"></path><path d="M717.8 114.5c-83.5 0-158.4 65.4-211.2 122-52.7-56.6-127.7-122-211.2-122-159.5 0-273.9 129.3-273.9 288.9C21.5 562.9 429.3 913 506.6 913s485.1-350.1 485.1-509.7c0.1-159.5-114.4-288.8-273.9-288.8z" fill="#FAFCFB" p-id="2810"></path><path d="M506.6 926c-22 0-61-20.1-116-59.6-51.5-37-109.9-86.4-164.6-139-65.4-63-217.5-220.6-217.5-324 0-81.4 28.6-157.1 80.6-213.1 53.2-57.2 126.4-88.8 206.3-88.8 40 0 81.8 14.1 124.2 41.9 28.1 18.4 56.6 42.8 86.9 74.2 30.3-31.5 58.9-55.8 86.9-74.2 42.5-27.8 84.3-41.9 124.2-41.9 79.9 0 153.2 31.5 206.3 88.8 52 56 80.6 131.7 80.6 213.1 0 103.4-152.1 261-217.5 324-54.6 52.6-113.1 102-164.6 139-54.8 39.5-93.8 59.6-115.8 59.6zM295.4 127.5c-72.6 0-139.1 28.6-187.3 80.4-47.5 51.2-73.7 120.6-73.7 195.4 0 64.8 78.3 178.9 209.6 305.3 53.8 51.8 111.2 100.3 161.7 136.6 56.1 40.4 88.9 54.8 100.9 54.8s44.7-14.4 100.9-54.8c50.5-36.3 108-84.9 161.7-136.6 131.2-126.4 209.6-240.5 209.6-305.3 0-74.9-26.2-144.2-73.7-195.4-48.2-51.9-114.7-80.4-187.3-80.4-61.8 0-127.8 38.5-201.7 117.9-2.5 2.6-5.9 4.1-9.5 4.1s-7.1-1.5-9.5-4.1C423.2 166 357.2 127.5 295.4 127.5z" fill="#141414" p-id="2811"></path><path d="M353.9 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2812"></path><path d="M659.3 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2813"></path><path d="M411.6 538.5c0 52.3 42.8 95 95 95 52.3 0 95-42.8 95-95v-31.7h-190v31.7z" fill="#5B5143" p-id="2814"></path><path d="M506.6 646.5c-59.6 0-108-48.5-108-108v-31.7c0-7.2 5.8-13 13-13h190.1c7.2 0 13 5.8 13 13v31.7c0 59.5-48.5 108-108.1 108z m-82-126.7v18.7c0 45.2 36.8 82 82 82s82-36.8 82-82v-18.7h-164z" fill="#141414" p-id="2815"></path><path d="M450.4 578.9a54.7 27.5 0 1 0 109.4 0 54.7 27.5 0 1 0-109.4 0Z" fill="#EA64F9" p-id="2816"></path><path d="M256 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2817"></path><path d="M703.3 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2818"></path></svg>',
click () {alert('捐赠地址:https://ld246.com/sponsor')},
]
Это похоже на язык JavaScript.
Текст описывает внешний вид элементов интерфейса, но не содержит кода для их создания или работы с ними. | | Объяснение | По умолчанию | | - | - | - | | delay | Интервал устранения дребезга предварительного просмотра в миллисекундах | 1000 | | maxWidth | Максимальная ширина области предварительного просмотра | 800 | | mode | Режим отображения: оба, редактор | «оба» | | url | Запрос на анализ md | — | | parse | Предварительный просмотр обратного вызова (элемент: HTMLElement) | — | | transform | Обратный вызов перед рендерингом (html: строка): строка | — |
Объяснение | По умолчанию | |
---|---|---|
current | Текущая тема Markdown | «light» |
list | Выбор списка тем Markdown | { «ant-design»: «Ant Design», dark: «Dark», light: «Light», wechat: «WeChat» } |
path | Путь CSS | https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/css/content-theme |
Объяснение | По умолчанию | |
---|---|---|
enable | Включить ли подсветку синтаксиса кода | Да |
style | Для необязательных значений см. Chroma | github |
lineNumber | Включить ли нумерацию строк | Нет |
Объяснение | По умолчанию | |
---|---|---|
autoSpace | Автопробел | Нет |
fixTermTypo | Автоматическая коррекция терминологии | Нет |
toc | Вставить оглавление | Нет |
footnotes | Сноски | Да |
codeBlockPreview | Отображать ли блоки кода в режимах wysiwyg и ir | Да |
mathBlockPreview | Отображать ли математические блоки в режимах wysiwyg и ir | Да |
paragraphBeginningSpace | Два пробела перед абзацем | Нет |
sanitize | Использовать XSS | Да |
listStyle | Добавить атрибут данных стиля | Нет |
linkBase | Префикс относительного пути ссылки | '' |
linkPrefix | Префикс ссылки | '' |
mark | Включить тег метки | Нет |
Объяснение | По умолчанию | |
---|---|---|
inlineDigit | Разрешены ли числа после встроенной математической формулы, начинающейся с $ | Нет |
macros | Определение макроса, передаваемое при рендеринге с помощью MathJax | {} |
engine | Механизм рендеринга математических формул: KaTeX, MathJax | 'KaTeX' |
По умолчанию: [«desktop», «tablet», «mobile», «mp-wechat», «zhihu»]
Объяснение | По умолчанию | |
---|---|---|
key | Пользовательский идентификатор действия, не пустой. | — |
tooltip | Подсказка | — |
text | Текст кнопки | — |
className | Класс кнопки | — |
click(key: string) | Событие клика | — |
Объяснение | По умолчанию | |
---|---|---|
parse | Выполнять ли анализ md | Да |
delay | Интервал устранения дребезга подсказки в миллисекундах | 200 |
emoji | Можно выбрать смайлик по умолчанию из lute/emoji_map, или можно настроить | { '+1': '👍', '-1': '👎', 'heart': '❤️', 'cold_sweat': '😰' } |
emojiTail | Общий смайлик | — |
emojiPath | Путь к смайликам | https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/images/emoji |
extend: IHintExtend[] | @/# и другое автоматическое расширение ключевых слов | [] |
interface IHintData {
html: string;
value: string;
}
interface IHintExtend {
key: string;
hint?(value: string): IHintData[] | Promise<IHintData[]>;
}
format
для преобразования.// POST data
xhr.send(formData); // formData = FormData.append("file[]", File)
// return data
{
"msg": "",
"code": 0,
"data": {
"errFiles": ['filename', 'filename2'],
"succMap": {
"filename3": "filepath3",
"filename3": "filepath3"
}
}
}
linkToImgUrl
может передавать адреса внешних изображений в буфере обмена на сервер для сохранения и обработки. Структура данных следующая:// POST data
xhr.send(JSON.stringify({url: src})); // src — это адрес изображения за пределами станции
// return data
{
msg: '',
code: 0,
data : {
originalURL: '',
url: ''
}
}
Объяснение | По умолчанию | |
---|---|---|
url | URL загрузки, пустое значение не вызовет событий, связанных с загрузкой | '' |
max | Максимальный размер файла для загрузки в байтах | |
--- | --- | |
linkToImgUrl | Когда в буфере обмена есть адрес изображения, используйте этот URL для повторной загрузки. | |
linkToImgCallback | Обработчик обратного вызова при загрузке адреса картинки. | |
linkToImgFormat | Преобразует данные, возвращённые сервером, чтобы они соответствовали встроенной структуре данных (responseText: string): string. | |
success | Обработчик успешного завершения загрузки (editor: HTMLPreElement, msg: string). | |
error | Обработчик сбоя загрузки (msg: string). | |
token | Проверка загрузки CORS, заголовок — X-Upload-Token. | |
withCredentials | Контроль доступа между сайтами. | |
headers | Настройки заголовка запроса. | |
filename | Очистка имён файлов (name: string): строка | name => name.replace(/\W/g, ''). | |
accept | Тип загрузки файла, такой же, как input accept. | |
validate | Проверяет и возвращает true в случае успеха, иначе возвращает сообщение об ошибке (files: File[]) => string | boolean. | |
handler(files: File[]) => string | null | Promise | Promise | Пользовательская загрузка, возвращает сообщение об ошибке при возникновении ошибки. | |
format | Преобразование данных, возвращённых сервером, для соответствия встроенной структуре данных (files: File[], responseText: string): string. | |
file(files: File[]): File[] | Promise<File[]> | Обработка загруженного файла перед возвратом. | |
setHeaders | Использование возвращаемого значения для установки заголовка перед загрузкой (): {[key: string]: string}. | |
extraData | Добавление данных в FormData {[key: string]: string | Blob}. |
multiple | Разрешение множественной загрузки файлов. | |
fieldName | Ключ имени поля. |
Объяснение | По умолчанию | |
---|---|---|
enable | Поддержка изменения размера. | false |
position | Позиция столбца перетаскивания: «top», «bottom». | «bottom» |
after | Обработчик по завершении перетаскивания (height: number). | - |
Объяснение | По умолчанию | |
---|---|---|
preview | Предварительный просмотр className элемента. | '' |
Объяснение | По умолчанию | |
---|---|---|
index | Индекс полноэкранного режима. | 90 |
Объяснение | По умолчанию | |
---|---|---|
enable | Инициализация отображения контура. | false |
position | Расположение контура: «left», «right». | «left» |
Объяснение | |
---|---|
exportJSON(markdown: string) | Получение JSON из markdown. |
getValue() | Получение содержимого редактора. |
getHTML() | Получение содержимого области предварительного просмотра. |
insertValue(value: string, render = true) | Вставка содержимого в фокус с рендерингом markdown по умолчанию. |
focus() | Фокусировка на редакторе. |
blur() | Размытие редактора. |
disabled() | Отключение редактора. |
enable() | Включение редактора. |
getSelection(): string | Возвращает выбранную строку. |
setValue(markdown: string, clearStack = false) | Установка содержимого редактора. |
clearStack() | Удаление стека отмены и повтора. |
renderPreview(value?: string) | Установка содержимого области предварительного просмотра. |
getCursorPosition():{top: number, left: number} | Получение позиции фокуса. |
deleteValue() | Удаление выделенного содержимого. |
updateValue(value: string) | Обновление выделенного содержимого. |
isUploading() | Проверка того, продолжается ли загрузка. |
clearCache() | Очистка кеша. |
disabledCache() | Отключение кеширования. |
enableCache() | Включение кэширования. |
html2md(value: string) | HTML в md. |
tip(text: string, time: number) | Уведомление. Время 0 всегда будет отображаться. |
setPreviewMode(mode: "both" | "editor") | Установка режима предварительного просмотра. |
setTheme(theme: "dark" | "classic", contentTheme?: string, codeTheme?: string, contentThemePath?: string) |
getCurrentMode(): string | Получение текущего режима редактирования редактора. |
destroy() | Уничтожение vditor. |
getCommentIds(): {id: string, top: number}[] | Получение всех комментариев. |
hlCommentIds(ids: string[]) | Подсветка комментария по Ids. |
unHlCommentIds(ids: string[]) | Отмена выделения комментария по Ids. |
removeCommentIds(removeIds: string[]) | Удаление комментария по Ids. |
method.min.js
и напрямую вызовите. Vditor.mermaidRender(document)
```js
import VditorPreview from 'vditor/dist/method.min'
VditorPreview.mermaidRender(document)
preview
со следующими параметрами:previewElement: HTMLDivElement, // Используйте этот элемент для рендеринга
markdown: string, // Исходный Markdown, который будет отображаться
options?: IPreviewOptions {
mode: "dark" | "light";
anchor?: number; // 0: не отображать, 1: отображать слева, 2: отображать справа
customEmoji?: { [key: string]: string }; // Пользовательские эмодзи, по умолчанию {}
lang?: (keyof II18nLang); // Язык, по умолчанию 'zh_CN'
emojiPath?: string; // Путь к изображению эмодзи
hljs?: IHljs; // См. параметры.preview.hljs
speech?: { // Чтение выбранного содержимого
enable?: boolean,
};
math?: IMath; // Конфигурация рендеринга математических формул
transform?(html: string): string; // Обратный вызов перед рендерингом
after?(); // Обратный вызов после рендеринга
cdn?: string; // Собственный адрес CDN
lazyLoadImage?: string; // используйте «https://cdn.jsdelivr.net/npm/vditor/dist/images/img-loading.svg», чтобы лениво загрузить изображение
markdown?: options.preview.markdown;
renderers?: ILuteRender; // Пользовательский метод рендеринга https://ld246.com/article/1588412297062
}
method.min.js
и index.min.js
нельзя вводить одновременноОбъяснение | |
---|---|
previewImage(oldImgElement: HTMLImageElement, lang: keyof II18n = "zh_CN", theme = "classic") | Нажмите на изображение, чтобы просмотреть |
mermaidRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) | Рендеринг блок-схемы/последовательной диаграммы/диаграммы Ганта |
flowchartRender(element: HTMLElement, cdn = options.cdn) | рендеринг flowchart.js |
codeRender(element: HTMLElement) | Добавьте кнопку копирования для блока кода в элементе |
chartRender(element: (HTMLElement| Document) = document, cdn = options.cdn, theme = options.theme) | рендеринг диаграммы |
plantumlRender(element: (HTMLElement| Document) = document, cdn = options.cdn) | рендеринг plantuml |
abcRender(element: (HTMLElement| Document) = document, cdn = options.cdn) | рендеринг нотной записи |
outlineRender(contentElement: HTMLElement, targetElement: Element, vditor?: IVditor) | рендеринг структуры |
md2html(mdText: string, options?: IPreviewOptions): Promise<string> | Текст Markdown преобразуется в HTML, для этого метода необходимо использовать асинхронное программирование |
preview(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions) | Отображение статьи Markdown на странице |
highlightRender(hljsOption?: IHljs, element?: HTMLElement | Document, cdn = options.cdn) | Выделите блок кода в элементе |
mediaRender(element: HTMLElement) | Рендеринг как специфическая ссылка в виде видео, аудио, встроенного iframe |
mathRender(element: HTMLElement, options?: {cdn?: string, math?: IMath}) | Рендеринг математических формул |
speechRender(element: HTMLElement, lang?: (keyof II18nLang)) | Прочитайте выбранный текст |
graphvizRender(element: HTMLElement, cdn?: string) | Рендеринг graphviz |
lazyLoadImageRender(element: (HTMLElement | Document) = document) | Рендеринг отложенной загрузки изображения |
setCodeTheme (codeTheme: string, cdn = options.cdn) | обновить тему кода |
setContentTheme (contentTheme: string, path: string) | обновить основную тему |
mindmapRender (element: (HTMLElement | Document) = document, cdn = options.cdn, theme = options.theme) | Рендеринг интеллект-карты |
Установите node LTS версии
Скачайте последний код и распакуйте его
Запустите npm install
в корневом каталоге
npm run
Запуск локального сервера, откройте http://localhost:9000
Измените код.
Соберите пакет кода в каталог dist с помощью команды npm run build
.
Благодаря механизму загрузки по требованию, стандартным CDN является https://cdn.jsdelivr.net/npm/vditor@номер версии.
Если вы изменили код или вам нужно использовать собственный CDN, выполните следующие действия:
Пожалуйста, внимательно прочитайте CHANGELOG перед обновлением версии.
Vditor использует открытую лицензию MIT.
На начальном этапе разработки Sym мы напрямую использовали WYSIWYG редактор форматированного текста. В то время HTML-редакторы были очень популярны, и было очень удобно цитировать их в проекте, что также соответствовало привычкам пользователей того времени.
Позже появление Markdown постепенно изменило типографику всех. Кроме того, некоторые другие наши проекты предназначены для программистов, поэтому переход на md также является общей тенденцией. Мы выбрали CodeMirror, который является отличным редактором, он предоставляет богатый программный интерфейс для разработчиков, а также совместим с различными браузерами. Это хорошо.
Позже, когда бизнес-потребности наших проектов обострились, использование CodeMirror иногда кажется более «громоздким». Например, для реализации автоматического заполнения списка имён пользователей, вставки эмодзи, загрузки файлов и т. д. требуется более глубокая вторичная разработка, и эти бизнес-требования точно распространены и необходимы во многих сценариях проекта.
Наконец, мы решили сами реализовать редактор в Sym. После нескольких версий редактор Sym стал зрелым. В сообществе LianDi, которым мы управляем, люди спрашивали нас, можем ли мы отделить редактор для общего использования. В то же время наш основной программист переднего плана V также чувствовал себя немного перегруженным поддержанием редакторов, разбросанных по различным проектам, плюс хорошее впечатление от TypeScript, поэтому я решил использовать ts для реализации нового редактора на стороне браузера.
Так родился Vditor.
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.