предисловие
В конце 2018 года автор получил задание на разработку — построить открытую платформу для ИИ-проектов, в которой документы продукта конвертируются в уценочные документы в формате HTML. Учитывая мгновенное обновление документа, информация о документе оформляется в виде Ajax-интерфейса. Таким образом, фон управления должен только преобразовать содержимое формы textarea в формат HTML с помощью синтаксического анализатора уценки, а затем сохранить содержимое уценки и преобразованный HTML-документ в базу данных.
После того, как основные требования будут выполнены, для лучшего взаимодействия с пользователем рассмотрите возможность добавления часто используемых функций редактирования. Улучшенная версия не только поддерживает часто используемые функции редактирования текста, но также реализует настройку пользовательского интерфейса и настраивает синтаксический анализатор. Чтобы принести пользу идущей стороне и накопить некоторый опыт работы с открытым исходным кодом, автор будет использовать компонент реагирования.react-markdown-editor-liteОн был упакован, преобразован и выпущен для сообщества с открытым исходным кодом.
предварительный просмотр
онлайн опытГарри Чен 0506.GitHub.IO/react-mark…
Функции
- Легкий, основанный на React
- Пользовательский интерфейс можно настроить, например, отображать только область редактирования или область предварительного просмотра.
- Поддержка пользовательского анализатора уценки, подсветки синтаксиса и т. д.
- Поддержка общих функций редактирования уценки, таких как выделение полужирным шрифтом, курсивом и т. д.
- Поддержка синхронной прокрутки области редактирования и области предварительного просмотра.
Опыт разработки
-
Текстовый редактор
Большинство распространенных редакторов, в том числе редакторы форматированного текста, используют свойства contenteditable определенных элементов, таких как элементы div, и взаимодействуют с такими API, как selection, range и execCommand, для реализации функций редактирования форматированного текста. Реализация здесь сложнее, поэтому есть "Почему вы говорите, что редактор форматированного текста — это провал?"Это утверждение.
В редакторе уценки основным содержимым обработки является обычный текст с простым синтаксисом, сложность относительно низкая, а входной тег имеет собственное событие onSelect, которое может легко получить информацию о выборе (выбрать начальную позицию и выбрать текстовое значение). , Поэтому, если вы хотите реализовать функцию редактирования, вам нужно только преобразовать содержимое для изменения, а затем повторно склеить начало и конец, и все готово.
-
парсинг уценки
Проанализировал несколько популярных парсеров уценки в сообществе, самые популярные из них:markdown, markdown-it, markedи т.п. Учитывая масштабируемость и стабильность, я рекомендую использовать markdown-it в качестве лексического парсера для уценки, потому что парсер имеет множество плагинов и поддерживает подсветку синтаксиса.
-
Синхронизированная прокрутка
При выборе редактирования столбца прокрутите область редактирования слева, а область предварительного просмотра справа может автоматически прокручиваться до соответствующей области. План относится кНаучит вас, как реализовать ввод уценки на основе реакции + онлайн-редактор с мгновенным предварительным просмотром со 100 строками кода (1)". Просто вычислите значение отношения максимального диапазона прокрутки между элементом контейнера поля ввода и элементом контейнера поля предварительного просмотра, а затем выполните соответствующее преобразование соотношения в соответствии с scrollTop самого активного элемента прокрутки, после чего вы сможете узнать значение scrollTop элемента противоположный район.
-
О UI
- Библиотека шрифтов проекта выбирает стиль Font Awesome и выбирает только некоторые значки, необходимые для проекта.
- Общий css редактора можно настроить в виде глобального переопределения. В настоящее время поддерживаются только серые темы.
- Область отображения редактора включает строку меню, редактор, область предварительного просмотра и панель инструментов.Настроив свойство конфигурации компонента, можно выбрать область отображения по умолчанию.
Install
npm install react-markdown-editor-lite --save
Props
| Property | Description | Type | default | Remarks |
|---|---|---|---|---|
| value | markdown content | String | '' | required |
| style | component container style | Object | {height: '100%'} | not required |
| config | component config | Object | {view: {...}, logger: {...}} | not required |
| config.view | component UI | Object | {menu: true, md: true, html: true} | |
| config.htmlClass | Html section class attribute | String | <Empty string> |
|
| config.markdownClass | Markdown section class attribute | String | <Empty string> |
|
| config.imageUrl | default image url | String | '' | |
| config.linkUrl | default link url | String | '' | |
| config.table | table maximum value of row and column | Object | {maxRow: 4, maxCol: 6} | |
| config.logger | logger in order to undo or redo | Object | {interval: 3000} | |
| config.synchScroll | Does it support synch scroll? | Boolean | true | |
| config.imageAccept | Accept image extensions, such as .jpg,.png
|
String | <Empty string> |
|
| onChange | emitting when editor has changed | Function | ({html, md}) => {} | not required |
| onImageUpload | when image uploaded, callback emitting will get image markdown text | (file: File, callback: (url: string) => void) => void; | ({file, callback}) => {} | not required |
| renderHTML | Render markdown text to HTML. You can return either string, function or Promise | (text: string) => string|function|Promise | none | required |
Example
'use strict';
import React from 'react'
import ReactDOM from 'react-dom'
import MdEditor from 'react-markdown-editor-lite'
import MarkdownIt from 'markdown-it'
import emoji from 'markdown-it-emoji'
import subscript from 'markdown-it-sub'
import superscript from 'markdown-it-sup'
import footnote from 'markdown-it-footnote'
import deflist from 'markdown-it-deflist'
import abbreviation from 'markdown-it-abbr'
import insert from 'markdown-it-ins'
import mark from 'markdown-it-mark'
import tasklists from 'markdown-it-task-lists'
import hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-light.css'
// import 'highlight.js/styles/github.css'
import './index.less';
const MOCK_DATA = "Hello.\n\n * This is markdown.\n * It is fun\n * Love it or leave it."
export default class Demo extends React.Component {
mdEditor = null
mdParser = null
constructor(props) {
super(props)
// initial a parser
this.mdParser = new MarkdownIt({
html: true,
linkify: true,
typographer: true,
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value
} catch (__) {}
}
return '' // use external default escaping
}
})
.use(emoji)
.use(subscript)
.use(superscript)
.use(footnote)
.use(deflist)
.use(abbreviation)
.use(insert)
.use(mark)
.use(tasklists, { enabled: this.taskLists })
this.renderHTML = this.renderHTML.bind(this)
}
handleEditorChange({html, md}) {
console.log('handleEditorChange', html, md)
}
handleImageUpload(file, callback) {
const reader = new FileReader()
reader.onload = () => {
const convertBase64UrlToBlob = (urlData) => {
let arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], {type:mime})
}
const blob = convertBase64UrlToBlob(reader.result)
setTimeout(() => {
// setTimeout 模拟异步上传图片
// 当异步上传获取图片地址后,执行calback回调(参数为imageUrl字符串),即可将图片地址写入markdown
callback('https://avatars0.githubusercontent.com/u/21263805?s=40&v=4')
}, 1000)
}
reader.readAsDataURL(file)
}
renderHTML(text) {
// 模拟异步渲染Markdown
return new Promise((resolve) => {
setTimeout(() => {
resolve(this.mdParser.render(text))
}, 1000)
})
}
handleGetMdValue = () => {
this.mdEditor && alert(this.mdEditor.getMdValue())
}
handleGetHtmlValue = () => {
this.mdEditor && alert(this.mdEditor.getHtmlValue())
}
render() {
return (
<div>
<nav>
<button onClick={this.handleGetMdValue} >getMdValue</button>
<button onClick={this.handleGetHtmlValue} >getHtmlValue</button>
</nav>
<section style="height: 500px">
<MdEditor
ref={node => this.mdEditor = node}
value={MOCK_DATA}
style={{height: '400px'}}
renderHTML={this.renderHTML}
config={{
view: {
menu: true,
md: true,
html: true
},
imageUrl: 'https://octodex.github.com/images/minion.png'
}}
onChange={this.handleEditorChange}
onImageUpload={this.handleImageUpload}
/>
</section>
</div>
)
}
}
наконец
Добро пожаловать в использование и обратную связь,адрес проекта (GitHub.com/Гарри Чен05…), ваши лайки будут моей отличной мотивацией 😊