我正在使用slate.js编写一个标记文本编辑器。我正在尝试实现以下实时呈现效果(来自泰波拉):

如你所见,
由于MarkdownPreview的示例,我已经实现了第一项,下面是它的代码(取自板岩储存库):
import Prism from 'prismjs'
import React, { useCallback, useMemo } from 'react'
import { Slate, Editable, withReact } from 'slate-react'
import { Text, createEditor, Descendant } from 'slate'
import { withHistory } from 'slate-history'
import { css } from '@emotion/css'
// eslint-disable-next-line
;Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
const MarkdownPreviewExample = () => {
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
const decorate = useCallback(([node, path]) => {
const ranges = []
if (!Text.isText(node)) {
return ranges
}
const getLength = token => {
if (typeof token === 'string') {
return token.length
} else if (typeof token.content === 'string') {
return token.content.length
} else {
return token.content.reduce((l, t) => l + getLength(t), 0)
}
}
const tokens = Prism.tokenize(node.text, Prism.languages.markdown)
let start = 0
for (const token of tokens) {
const length = getLength(token)
const end = start + length
if (typeof token !== 'string') {
ranges.push({
[token.type]: true,
anchor: { path, offset: start },
focus: { path, offset: end },
})
}
start = end
}
return ranges
}, [])
return (
<Slate editor={editor} value={initialValue}>
<Editable
decorate={decorate}
renderLeaf={renderLeaf}
placeholder="Write some markdown..."
/>
</Slate>
)
}
const Leaf = ({ attributes, children, leaf }) => {
return (
<span
{...attributes}
className={css`
font-weight: ${leaf.bold && 'bold'};
font-style: ${leaf.italic && 'italic'};
text-decoration: ${leaf.underlined && 'underline'};
${leaf.title &&
css`
display: inline-block;
font-weight: bold;
font-size: 20px;
margin: 20px 0 10px 0;
`}
${leaf.list &&
css`
padding-left: 10px;
font-size: 20px;
line-height: 10px;
`}
${leaf.hr &&
css`
display: block;
text-align: center;
border-bottom: 2px solid #ddd;
`}
${leaf.blockquote &&
css`
display: inline-block;
border-left: 2px solid #ddd;
padding-left: 10px;
color: #aaa;
font-style: italic;
`}
${leaf.code &&
css`
font-family: monospace;
background-color: #eee;
padding: 3px;
`}
`}
>
{children}
</span>
)
}
const initialValue: Descendant[] = [
{
type: 'paragraph',
children: [
{
text:
'Slate is flexible enough to add **decorations** that can format text based on its content. For example, this editor has **Markdown** preview decorations on it, to make it _dead_ simple to make an editor with built-in Markdown previewing.',
},
],
},
{
type: 'paragraph',
children: [{ text: '## Try it out!' }],
},
{
type: 'paragraph',
children: [{ text: 'Try it out for yourself!' }],
},
]
export default MarkdownPreviewExample我的问题是,如何落实第二及第三项呢?我已经考虑了很长时间,但没有找到任何好的方法来实现它们。
发布于 2022-09-03 08:41:21
好消息:
Slate.js为每个样式呈现一个新元素。感谢您发布的实时演示链接,很明显DOM正在保存您的标记的state (这意味着如果需要的话,我们可以在板岩上添加操作)。坏消息:
VS code体验?是的,请!)我们能做什么?
简易方式:
在我们的项目中使用摩纳哥编辑器。根据我的经验,它在编码和格式化技术文本方面更好(也许这就是VS code背后的引擎)。
不那么容易的方式:
我们可以做一个更简单的实现--一个带有原始文本的面板和另一个预览面板(顺便说一句,这正是在VS code中编辑标记文件时发生的事情)。这样,我们就可以始终呈现出反映我们最近变化的观点。首先,您可以使用这个项目来完成它,并在其中添加一些调整,以满足您的要求。
的艰难之路:
使用slate.js commands (一般概念阅读这位医生 +有用的示例)。这种方法可以让slate处理负载,但也需要您深入研究该项目。请注意,您可以注册自定义命令和查询,以满足您的需要,而无需中断工作管道(请阅读这)。
疯狂的方式
尝试通过在呈现的元素之上使用自定义事件来覆盖板岩。这可能是棘手的,但如果你喜欢玩项目内部和注入价值的动态。不过,不太推荐
我的建议
创建一个将应用所需markdown style的自定义命令(例如:粗体)
使用板岩处理程序跟踪space键命中并使用您的命令
function onKeyDown(event, editor, next) {
if (event.key == 'Enter') {
// TODO: add markdown style
editor.applyMarkdownBold() // applyMarkdownBold is a made-up name for your custom command
} else {
return next()
}
}我知道-这个示例将对所有文本应用粗体样式,但是-如果将它与range selection结合起来,您将得到编辑器中相关区域所需的样式(同样- 文档用于拯救)
从这一点开始--通过按下键或通过单击添加标记字符(使用事件+查询+命令)应用特定的选择只是时间问题。
https://stackoverflow.com/questions/72500275
复制相似问题