1. Понимание просезеркала
prosemirorrЭто не готовый редактор, а редактор форматированного текста, построенный с помощью ряда модулей.Основные модули в основном включают следующие четыре
-
prosemirror-model: Отвечает за структуру контента просезеркала. Он определяет модель документа редактора, которая используется для описания структуры данных содержимого редактора и реализует атомарную операцию над содержимым редактора. Реализована система индексации для обработки информации о местоположении. Также предоставляет Parser из DOM -> ProsemirrNode и обратный Serilizer.
-
prosemirror-transfrom: отвечает за изменение содержимого редактирования. Изменения документа осуществляются поэтапно. Transform инкапсулирует серию API, которые работают с содержимым на основе шага. Шаг выполняет операцию над содержимым документа и записывает измененную информацию через StepMap, которую можно использовать для отслеживания изменения позиции.
-
prosemirror-state: Отвечает за описание состояния всего редактора. Включая содержимое документа, информацию об избирательных округах, все типы узлов и транзакцию, основанную на преобразовании, транзакция в основном улучшает управление избирательными округами и записями о состоянии. В то же время он предоставляет мощную систему подключаемых модулей для реализации возможности вмешательства пользователя в процесс обновления статуса.
-
prosemirror-view: Отвечает за отрисовку представления, которое реализует отрисовку из состояния в представление. Отслеживайте или перехватывайте действия пользователей и вносите исправления, вносите соответствующие изменения в состояние и, наконец, сравниваете окончательный результат рендеринга решений dom и состояния.
Эти четыре модуля реализуют основные функции prosemirror, но правила, такие как то, какие клавиши имеют какое поведение, должны быть реализованы пользователем самостоятельно.К счастью, официальная библиотека предоставляет prosemirror-commands, prosemirror-history, prosemirror-keymap и другие библиотеки для Помогите нам Легче реализовать редактор.
2. Определение узла
Узлы, отображаемые в prosemirror, должны иметь соответствующие определения в схеме, а узлы, которые могут быть определены в схеме, делятся на два типа.nodeа такжеmark,
Node
Узел — это узел в общепринятом понимании, который делится на блочный или встроенный. Мы можем определить узел, который будет вести себя в просемиошибке:
paragraph: {
group: "block",
content: "text*",
parseDOM: [{tag: 'p'}],
toDOM(node) { return ['p', 0] }
}
Узел «абзац» определяется, как указано выше: группа означает, что это группа блоков; контент означает, что он может содержать любой текст; parseDOM означает его синтаксический анализ.<p>xxx</p>;toDOM означает, что он отображается как<p>xxx</p>, дочерний узел вставляется с позиции 0, можно просмотреть дополнительную конфигурациюNodeSpec, содержимое представляет собой обычную строку, вы можете использовать имя узла или имя группы.
Mark
Mark — это особый тип Schema. Его производительность отличается от Node. Mark в основном воздействует на встроенные узлы, добавляя стили или добавляя другую информацию к встроенным элементам. Дополнение к описанию документации.
bold: {
parseDOM: [{tag: 'strong'}],
toDOM(node) { return ['strong', 0]}
}
Определите Метку полужирным шрифтом, как указано выше, DOM при разборе и рендеринге. Дополнительные ссылки на определение:MarkSpec
Attributes
И Node, и Mark могут прикреплять некоторую информацию, но поддерживаемые свойства должны быть определены во время инициализации.
paragraph: {
group: "block",
content: "text*",
attrs: {
align: {
default: 'left'
}
}
}
Как и выше, определен узел абзаца, содержащий align в attrs, который можно использовать как простое хранилище информации или для изменения вывода рендеринга с помощью toDOM.
3. Структура документа
содержание
Содержимое просемирора описывается как дерево, а его атрибуты функций (isBlock, isInline и т. д.) определяются определяемыми нами функциями узла.
Содержимое Node представлено Фрагментом, а содержимое Фрагмента представляет собой массив, составленный из Узлов Prosemirror описывает документ через древовидную структуру, образованную такой вложенностью.
показатель
prosemirror реализует набор индексных систем, используемых для представления документа в определенном месте, разделенных на два типа:
Первый больше похож на доступ к DOM, использование свойств массива содержимого для доступа к узлам и обход документа в виде дерева.
Во-вторых, это мощная система индексации.После того, как документ будет сведен, любая позиция в полузеркальном документе может быть представлена уникальным целым числом.
Для обычного DOM это древовидная структура.
В системе индексации просезеркала это дерево выравнивается и оговаривается:
- Позиция перед первым узлом всего документа равна нулю.
- Узлы, которые входят или выходят, не являются конечными узлами (то есть другое содержимое может содержать другое содержимое), считаются токеном. Следовательно, если документ начинается с абзаца, содержание абзаца считается позицией 1.
- Каждый контент в текстовом узле является токеном.
- Листовой узел (который не может содержать содержимое других узлов) также рассматривается как токен.
Согласно этому правилу представьте, что у нас есть указатель, индекс которого увеличивается на 1 при входе в узел с начала 0, увеличивается на 1 каждый раз при пересечении текстового содержимого, а также увеличивается на 1 при выходе из узла. , мы можем описать каждый документ в документе расположение.
Как показано выше, nodeSize можно понимать как расстояние, которое проходит наш указатель от входа до выхода из узла, поэтому соответствующий
<p>Размер узла равен 5,<blockquote>Размер узла равен 8. Таким образом, мы можем описать расположение и размер каждого узла. Эту информацию необходимо использовать во многих операциях в prosmirror.
В-четвертых, как изменить документ
После понимания вышеуказанного содержания у нас есть общее представление о структуре документа prosemirror, и следующим шагом будет попытка изменить данные документа. Давайте заменим содержимое официального сайта на Hello Prosemirror! .
анализировать
Согласно приведенному выше анализу, нам нужно изменить атрибут содержимого документа, или напрямую изменить текстовое содержимое, или удалить содержимое, а затем вставить его Мы выбираем первый метод для его достижения.
Обновление данных в prosemirror на самом деле является модификацией состояния. API updateState, предоставляемый состоянием, принимает новое состояние для обновления состояния. Представление экземпляра редактора помогает мне инкапсулировать этот шаг. API, доступный для внешнего мира, — это диспетчеризация.
Выше мы упомянули, что операцию модификации документа выполняетprosemirror-transformдостичь, иprosemirror-stateсерединаtrСвойство наследует преобразование, а состояние используется какprosemirror-viewАтрибут экземпляра.
Поэтому операцию обновления можно реализовать через представление.Документация API,ВидетьreplaceRangeWithЭтот API соответствует нашим потребностям,
from и to — введенные выше порядковые номера, представляющие позицию замены, node — новый узел, для текущей операции начальная точка замены from — это начальная позиция 0, а конечная позиция замены — конечная точка содержимого. содержимого документа, а узел можно создать с помощью схемы.
выполнить
Согласно приведенному выше анализу, операции по замене узла:
const { dispatch, state } = view;
const { schema, tr, doc } = state;
const { paragraph } = schema.nodes;
const textNode = schema.text('Hello Prosemirror!');
const newParagraph = paragraph.create(undefined, textNode);
dispatch(tr.replaceRangeWith(0, doc.content.size, newParagraph));
На этом замена контента завершена!
принцип
Итак, с точки зрения prosemirror, что делает replaceRangeWith?
Как упоминалось выше, операция преобразования документа реализуется пошагово, поэтому этот шаг фактически создает ReplaceStep для изменения документа.
Модификация документа пошагово не обязательно успешна. Результат представлен StepResult. В случае неудачи будет выдано сообщение об ошибке TransformError. В случае успеха будет возвращено содержимое нового документа. Преобразование сохранит содержимое старый документ в свойстве docs.Новое приложение применяется к атрибуту doc, а шаг сохраняется в атрибуте steps, который может реализовать операцию отмены. Наконец, обновите до состояния через distpach.
Следовательно, мы можем рассматривать state.tr как транзакцию, а каждый шаг можно рассматривать как атомарную операцию.Транзакция передается через диспетчеризацию и применяется к состоянию для вступления в силу, реализуя модификацию документа.
V. Резюме
Из вышеизложенного, краткого введения в некоторые концепции просезеркала, использования API и принципа обновления документа мы видим, что просемирор может четко описать структуру документа посредством абстракции данных. Он хорошо инкапсулирует работу документа, скрывает множество деталей и предоставляет множество удобных API.
Эта статья по-прежнему является лишь поверхностным введением в просезеркало, например, как обновляется документ, как визуализируется представление, как фиксируется и анализируется поведение пользователя... Есть еще много вещей, которые стоит изучить, и будет серию статей, чтобы представить их в будущем.
Добро пожаловать, чтобы указывать на ошибки или задавать вопросы, общаться друг с другом и развиваться вместе 😁