Closed guugg closed 11 months ago
默认获取数据是通过value={initialValue}
还是在useIsomorphicLayoutEffect
使用接口导入啊? @big-camel
使用序列化和反序列化
类似这里获取markdown,只不过序列化使用 editor.value https://github.com/editablejs/editable/blob/main/apps/docs/src/pages/playground.tsx#L319 同样需要这样初始化绑定解析器 https://github.com/editablejs/editable/blob/main/apps/docs/src/pages/playground.tsx#L291
在 useIsomorphicLayoutEffect 里面可以
const { onChange } = editor
editor.onChange = ()=> {
...
}
return () => {
editor.onChange = onChange
}
使用序列化和反序列化
类似这里获取markdown,只是序列化使用editor.value https://github.com/editablejs/editable/blob/main/apps/docs/src/pages/playground.tsx#L319 同样需要这样初始化绑定解析器 https://github.com/editablejs/editable/blob/main/apps/docs/src/pages/playground.tsx#L291
在使用IsomorphicLayoutEffect里面就可以
const { onChange } = editor editor.onChange = ()=> { ... } return () => { editor.onChange = onChange }
以前的文章部分含有markdown
,html
。 这怎么反序列化
import { MarkdownDeserializer } from '@editablejs/deserializer/markdown' import { HtmlDeserializer } from '@editablejs/deserializer/html'
import { MarkdownSerializer } from '@editablejs/serializer/markdown' import { HtmlSerializer } from '@editablejs/serializer/html'
useIsomorphicLayoutEffect(() => {
withMarkdownDeserializerPlugin(editor) //将markdown反序列化程序插件添加到编辑器中
withMarkdownSerializerPlugin(editor) // 将markdown序列化程序插件添加到编辑器中
withTextSerializerTransform(editor) // 将text 序列化程序转换添加到编辑器
withHTMLSerializerTransform(editor) // 将HTML序列化程序转换添加到编辑器
withMarkdownSerializerTransform(editor) // 将markdown序列化程序转换添加到编辑器
withHTMLDeserializerTransform(editor) // 将HTML反序列化程序转换添加到编辑器
withMarkdownDeserializerTransform(editor) // 将markdown反序列化程序转换添加到编辑器
HTMLDeserializer.withEditor(editor, withTitleHTMLDeserializerTransform, {})
HTMLSerializer.withEditor(editor, withTitleHTMLSerializerTransform, {})
const { onPaste, onChange } = editor
editor.onPaste = event => {
...
...
}
editor.onChange = () => {
const element = document.getElementById('text');
const text = element ? element.innerHTML : '';
const madst = MarkdownDeserializer.toMdastWithEditor(editor, text)
const contentc = MarkdownDeserializer.transformWithEditor(editor, madst)
editor.insertFragment(contentc)
console.log('接口:', contentc);
}
return () => {
editor.onPaste = onPaste
editor.onChange = onChange
}
}, [editor])
<div id="text"></div>
中的内容:
如果您看到这篇文章,表示您已经安装成功.
- `console.log`中
[ { "type": "paragraph", "children": [ { "text": "如果您看到这篇文章,表示您已经安装成功." } ] }, { "type": "heading-three", "children": [ { "fontSize": "20px", "bold": "bold", "text": "测试" } ] } ]
> Editable编辑器没有改变。一直刷新`console.log`
![屏幕截图 2023-09-02 120152.png](https://x.imgs.ovh/x/2023/09/02/64f2b70758c20.png)
鼠标点击,切换光标也会改变
鼠标点击,切换光标也会改变
我还是不会,太菜了。
如果<div id="text"></div>
里有HTML它识别成paragraph
了
如果您看到这篇文章,表示已经安装成功.
### 测试
- 测试
<a href="http://127.0.0.66/admin/manage-posts.php">主题开发者</a>
[
{
"type": "paragraph",
"children": [
{
"text": "如果您看到这篇文章,表示已经安装成功."
}
]
},
{
"type": "heading-three",
"children": [
{
"fontSize": "20px",
"bold": "bold",
"text": "测试"
}
]
},
{
"key": "6nnc17bke6s0",
"level": 0,
"start": 0,
"children": [
{
"type": "paragraph",
"children": [
{
"text": "测试"
}
]
}
],
"type": "unordered-list"
},
{
"type": "paragraph",
"children": [
{
"text": "<a href=\""
},
{
"href": "http://127.0.0.66/admin/manage-posts.php\">主题开发者</a",
"children": [
{
"text": "http://127.0.0.66/admin/manage-posts.php\">主题开发者</a"
}
],
"type": "link"
},
{
"text": ">"
}
]
}
]
还有就是,新文章是json
原识别是paragraph
有什么方法比较简单的,我数据来源是一个ID,然后通过函数还是变量加载数据自动判断类型使用下面的反序列,最后在
<EditableProvider editor={editor} value={initialValue}>
中的value
导入?
withMarkdownDeserializerPlugin(editor) //将markdown反序列化程序插件添加到编辑器中
withMarkdownSerializerPlugin(editor) // 将markdown序列化程序插件添加到编辑器中
withTextSerializerTransform(editor) // 将text 序列化程序转换添加到编辑器
withHTMLSerializerTransform(editor) // 将HTML序列化程序转换添加到编辑器
withMarkdownSerializerTransform(editor) // 将markdown序列化程序转换添加到编辑器
withHTMLDeserializerTransform(editor) // 将HTML反序列化程序转换添加到编辑器
withMarkdownDeserializerTransform(editor) // 将markdown反序列化程序转换添加到编辑器
HTMLDeserializer.withEditor(editor, withTitleHTMLDeserializerTransform, {})
HTMLSerializer.withEditor(editor, withTitleHTMLSerializerTransform, {})
const document = new DOMParser().parseFromString(html, TEXT_HTML)
const fragment = HTMLDeserializer.transformWithEditor(e, document.body)
e.insertFragment(fragment)
你也可以随时通过
MarkdownSerializer.withEditor(editor, withImageMarkdownSerializerTransform, {});
MarkdownDeserializer.withEditor(editor, withImageMarkdownDeserializerTransform, {});
这类接口自定义解析
import { Image } from '@editablejs/plugins';
import { MarkdownSerializerWithTransform } from '@editablejs/serializer/markdown';
export const withImageMarkdownSerializerTransform: MarkdownSerializerWithTransform = (next) => {
return (node, options = {}) => {
if (Image.isImage(node) && node.url) {
const { url } = node;
const wh = node.width && node.height ? `wh=${node.width}x${node.height}` : '';
return [
{
type: 'image',
url: wh ? url + (~url.indexOf('?') ? `&${wh}` : `?${wh}`) : url,
},
];
}
return next(node, options);
};
};
import { MarkdownDeserializerWithTransform } from '@editablejs/deserializer/markdown';
import { Image } from '@editablejs/plugins';
export const withImageMarkdownDeserializerTransform: MarkdownDeserializerWithTransform = (next) => {
return (node, options = {}) => {
const { type } = node;
if (type === 'image') {
const { url } = node;
let width: number | undefined = undefined;
let height: number | undefined = undefined;
const match = url.match(/wh=([\d.]+)x([\d.]+)/);
if (match) {
width = parseInt(match[1]);
height = parseInt(match[2]);
}
return [
Image.create({
url,
state: 'waitingUpload',
width,
height,
}),
];
}
return next(node, options);
};
};
const document = new DOMParser().parseFromString(html, TEXT_HTML) const fragment = HTMLDeserializer.transformWithEditor(e, document.body) e.insertFragment(fragment)
你也可以随时通过
MarkdownSerializer.withEditor(editor, withImageMarkdownSerializerTransform, {}); MarkdownDeserializer.withEditor(editor, withImageMarkdownDeserializerTransform, {});
这类接口自定义解析
import { Image } from '@editablejs/plugins'; import { MarkdownSerializerWithTransform } from '@editablejs/serializer/markdown'; export const withImageMarkdownSerializerTransform: MarkdownSerializerWithTransform = (next) => { return (node, options = {}) => { if (Image.isImage(node) && node.url) { const { url } = node; const wh = node.width && node.height ? `wh=${node.width}x${node.height}` : ''; return [ { type: 'image', url: wh ? url + (~url.indexOf('?') ? `&${wh}` : `?${wh}`) : url, }, ]; } return next(node, options); }; }; import { MarkdownDeserializerWithTransform } from '@editablejs/deserializer/markdown'; import { Image } from '@editablejs/plugins'; export const withImageMarkdownDeserializerTransform: MarkdownDeserializerWithTransform = (next) => { return (node, options = {}) => { const { type } = node; if (type === 'image') { const { url } = node; let width: number | undefined = undefined; let height: number | undefined = undefined; const match = url.match(/wh=([\d.]+)x([\d.]+)/); if (match) { width = parseInt(match[1]); height = parseInt(match[2]); } return [ Image.create({ url, state: 'waitingUpload', width, height, }), ]; } return next(node, options); }; };
import * as React from 'react'
import { useState } from 'react';
import {
EditableProvider,
ContentEditable,
useIsomorphicLayoutEffect,
Placeholder,
isTouchDevice,
Editable,
withEditable,
parseDataTransfer,
} from '@editablejs/editor'
import { Editor, createEditor, Range, Transforms } from '@editablejs/models'
import { MarkdownDeserializer } from '@editablejs/deserializer/markdown'
import { withPlugins, useContextMenuEffect, ContextMenu } from '@editablejs/plugins'
import { withHTMLSerializerTransform } from '@editablejs/plugins/serializer/html'
import { withTextSerializerTransform } from '@editablejs/plugins/serializer/text'
import {
withMarkdownSerializerTransform,
withMarkdownSerializerPlugin,
} from '@editablejs/plugins/serializer/markdown'
import { withHTMLDeserializerTransform } from '@editablejs/plugins/deserializer/html'
import {
withMarkdownDeserializerTransform,
withMarkdownDeserializerPlugin,
} from '@editablejs/plugins/deserializer/markdown'
import { withTitleHTMLSerializerTransform } from '@editablejs/plugin-title/serializer/html'
import { withTitleHTMLDeserializerTransform } from '@editablejs/plugin-title/deserializer/html'
import { withHistory } from '@editablejs/plugin-history'
import {
ToolbarComponent,
useToolbarEffect,
withToolbar,
Toolbar,
} from '@editablejs/plugin-toolbar'
import {
withInlineToolbar,
useInlineToolbarEffect,
InlineToolbar,
} from '@editablejs/plugin-toolbar/inline'
import {
withSideToolbar,
} from '@editablejs/plugin-toolbar/side'
import {
withSlashToolbar,
} from '@editablejs/plugin-toolbar/slash'
import { TitleEditor } from '@editablejs/plugin-title'
import { HTMLDeserializer } from '@editablejs/deserializer/html'
import { HTMLSerializer } from '@editablejs/serializer/html'
import { createInlineToolbarItems } from './components/configs/inline-toolbar-items'
import { checkMarkdownSyntax } from './components/configs/check-markdown-syntax'
import { createContextMenuItems } from './components/configs/context-menu-items'
import {
createToolbarItems,
} from './components/configs/toolbar'
export default function Editor_masin() {
const [initialValue, setInitialValue] = useState<{ type: string; children: { text: string }[] }[] | null>(null);
const [isFetching, setIsFetching] = useState(true);
const editor = React.useMemo(() => {
let editor = withEditable(createEditor())
//带历史记录
editor = withHistory(editor)
//插件
editor = withPlugins(editor)
//带工具栏
editor = withToolbar(editor)
//带内联工具栏
editor = withInlineToolbar(withToolbar(editor))
if (!isTouchDevice) {
editor = withSideToolbar(editor, {
match: n => !TitleEditor.isTitle(editor, n),
})
}
//带有斜线工具栏
editor = withSlashToolbar(editor, {
match: () => !Editor.above(editor, { match: n => TitleEditor.isTitle(editor, n) }),
})
return editor
}, [])
useIsomorphicLayoutEffect(() => {
const unsubscribe = Placeholder.subscribe(editor, ([node]) => {
if (
Editable.isFocused(editor) &&
Editor.isBlock(editor, node) &&
!TitleEditor.isTitle(editor, node)
)
return () => '编辑器块占位符'
})
return () => unsubscribe()
}, [editor])
useIsomorphicLayoutEffect(() => {
withMarkdownDeserializerPlugin(editor) // Adds a markdown deserializer plugin to the editor
withMarkdownSerializerPlugin(editor) // Adds a markdown serializer plugin to the editor
withTextSerializerTransform(editor) // Adds a text serializer transform to the editor
withHTMLSerializerTransform(editor) // Adds an HTML serializer transform to the editor
withMarkdownSerializerTransform(editor) // Adds a markdown serializer transform to the editor
withHTMLDeserializerTransform(editor) // Adds an HTML deserializer transform to the editor
withMarkdownDeserializerTransform(editor) // Adds a markdown deserializer transform to the editor
HTMLDeserializer.withEditor(editor, withTitleHTMLDeserializerTransform, {})
HTMLSerializer.withEditor(editor, withTitleHTMLSerializerTransform, {})
const { onPaste } = editor
editor.onPaste = (event) => {
const { clipboardData, type } = event
if (!clipboardData || !editor.selection) return onPaste(event)
const { text, fragment, html, files } = parseDataTransfer(clipboardData)
const isPasteText = type === 'pasteText'
if (!isPasteText && (fragment.length > 0 || files.length > 0)) {
return onPaste(event)
}
if (Range.isExpanded(editor.selection)) {
Transforms.delete(editor)
}
const anchor = Range.start(editor.selection)
onPaste(event)
// check markdown syntax
if (checkMarkdownSyntax(text, html) && editor.selection) {
const focus = Range.end(editor.selection)
Promise.resolve().then(() => {
const madst = MarkdownDeserializer.toMdastWithEditor(editor, text)
const content = MarkdownDeserializer.transformWithEditor(editor, madst)
editor.selection = {
anchor,
focus,
}
editor.insertFragment(content)
})
}
}
return () => {
editor.onPaste = onPaste
}
}, [editor])
//从text获取内容
useIsomorphicLayoutEffect(() => {
// 获取初始值
setTimeout(() => {
const textw = document.querySelector('#text');
const contentww = textw ? textw.innerHTML : '';
const madstw = MarkdownDeserializer.toMdastWithEditor(editor, contentww)
const contentw = MarkdownDeserializer.transformWithEditor(editor, madstw)
// 设置初始值
if (contentw && contentw.length > 0) {
setInitialValue(contentw as { type: string; children: { text: string }[] }[]);
} else {
setInitialValue([{ type: 'paragraph', children: [{ text: '🤣' }] }]);
}
setIsFetching(false);
}, 200);
}, []);
useContextMenuEffect(() => {
ContextMenu.setItems(editor, createContextMenuItems(editor))
}, editor)
useToolbarEffect(() => {
Toolbar.setItems(editor, createToolbarItems(editor))
}, editor)
useInlineToolbarEffect(() => {
InlineToolbar.setItems(editor, createInlineToolbarItems(editor))
}, editor)
if (isFetching) {
return <div>加载中...</div>; // 渲染加载状态
}
return (
<>
<EditableProvider
editor={editor}
value={initialValue || []}
>
<ToolbarComponent className='flex-wrap' editor={editor} />
<ContentEditable />
</EditableProvider>
</>
)
}
大佬,我是这样获取的,只能获取到MD格式。 我不知道怎么添加让它也支持获取到html格式。
现在的编辑器没有报任何错误
使用 HTMLDeserializer 相关api 就可以 from 阿里邮箱 iPhone------------------------------------------------------------------ @.> 日 期:2023年09月09日 17:50:19 @.> @.>; @.> 主 题:Re: [editablejs/editable] 数据转换保存跟获取转换数据,我实现不了 (Issue #134)
const document = new DOMParser().parseFromString(html, TEXT_HTML) const fragment = HTMLDeserializer.transformWithEditor(e, document.body) e.insertFragment(fragment)
你也可以随时通过 MarkdownSerializer.withEditor(editor, withImageMarkdownSerializerTransform, {}); MarkdownDeserializer.withEditor(editor, withImageMarkdownDeserializerTransform, {});
这类接口自定义解析 import { Image } from @./plugins'; import { MarkdownSerializerWithTransform } from @./serializer/markdown';
export const withImageMarkdownSerializerTransform: MarkdownSerializerWithTransform = (next) => {
return (node, options = {}) => {
if (Image.isImage(node) && node.url) {
const { url } = node;
const wh = node.width && node.height ? wh=${node.width}x${node.height}
: '';
return [
{
type: 'image',
url: wh ? url + (~url.indexOf('?') ? &${wh}
: ?${wh}
) : url,
},
];
}
return next(node, options);
};
};
import { MarkdownDeserializerWithTransform } from @./deserializer/markdown'; import { Image } from @./plugins';
export const withImageMarkdownDeserializerTransform: MarkdownDeserializerWithTransform = (next) => { return (node, options = {}) => { const { type } = node; if (type === 'image') { const { url } = node; let width: number | undefined = undefined; let height: number | undefined = undefined; const match = url.match(/wh=([\d.]+)x([\d.]+)/);
if (match) {
width = parseInt(match[1]);
height = parseInt(match[2]);
}
return [
Image.create({
url,
state: 'waitingUpload',
width,
height,
}),
];
}
return next(node, options);
}; };
import * as React from 'react' import { useState } from 'react'; import { EditableProvider, ContentEditable, useIsomorphicLayoutEffect, Placeholder, isTouchDevice, Editable, withEditable, parseDataTransfer, } from @./editor' import { Editor, createEditor, Range, Transforms } from @./models' import { MarkdownDeserializer } from @./deserializer/markdown' import { withPlugins, useContextMenuEffect, ContextMenu } from @./plugins' import { withHTMLSerializerTransform } from @./plugins/serializer/html' import { withTextSerializerTransform } from @./plugins/serializer/text' import { withMarkdownSerializerTransform, withMarkdownSerializerPlugin, } from @./plugins/serializer/markdown' import { withHTMLDeserializerTransform } from @./plugins/deserializer/html'
import { withMarkdownDeserializerTransform, withMarkdownDeserializerPlugin, } from @.***/plugins/deserializer/markdown'
import { withTitleHTMLSerializerTransform } from @./plugin-title/serializer/html' import { withTitleHTMLDeserializerTransform } from @./plugin-title/deserializer/html'
import { withHistory } from @.***/plugin-history'
import { ToolbarComponent, useToolbarEffect, withToolbar, Toolbar, } from @./plugin-toolbar' import { withInlineToolbar, useInlineToolbarEffect, InlineToolbar, } from @./plugin-toolbar/inline' import { withSideToolbar, } from @./plugin-toolbar/side' import { withSlashToolbar, } from @./plugin-toolbar/slash' import { TitleEditor } from @./plugin-title' import { HTMLDeserializer } from @./deserializer/html' import { HTMLSerializer } from @.***/serializer/html'
import { createInlineToolbarItems } from './components/configs/inline-toolbar-items' import { checkMarkdownSyntax } from './components/configs/check-markdown-syntax'
import { createContextMenuItems } from './components/configs/context-menu-items' import { createToolbarItems, } from './components/configs/toolbar'
export default function Editor_masin() { const [initialValue, setInitialValue] = useState<{ type: string; children: { text: string }[] }[] | null>(null); const [isFetching, setIsFetching] = useState(true);
const editor = React.useMemo(() => { let editor = withEditable(createEditor()) //带历史记录 editor = withHistory(editor) //插件 editor = withPlugins(editor) //带工具栏 editor = withToolbar(editor) //带内联工具栏 editor = withInlineToolbar(withToolbar(editor)) if (!isTouchDevice) { editor = withSideToolbar(editor, { match: n => !TitleEditor.isTitle(editor, n), }) } //带有斜线工具栏 editor = withSlashToolbar(editor, { match: () => !Editor.above(editor, { match: n => TitleEditor.isTitle(editor, n) }), }) return editor }, []) useIsomorphicLayoutEffect(() => { const unsubscribe = Placeholder.subscribe(editor, ([node]) => { if ( Editable.isFocused(editor) && Editor.isBlock(editor, node) && !TitleEditor.isTitle(editor, node) ) return () => '编辑器块占位符' }) return () => unsubscribe()
}, [editor]) useIsomorphicLayoutEffect(() => { withMarkdownDeserializerPlugin(editor) // Adds a markdown deserializer plugin to the editor withMarkdownSerializerPlugin(editor) // Adds a markdown serializer plugin to the editor withTextSerializerTransform(editor) // Adds a text serializer transform to the editor withHTMLSerializerTransform(editor) // Adds an HTML serializer transform to the editor withMarkdownSerializerTransform(editor) // Adds a markdown serializer transform to the editor withHTMLDeserializerTransform(editor) // Adds an HTML deserializer transform to the editor withMarkdownDeserializerTransform(editor) // Adds a markdown deserializer transform to the editor HTMLDeserializer.withEditor(editor, withTitleHTMLDeserializerTransform, {}) HTMLSerializer.withEditor(editor, withTitleHTMLSerializerTransform, {}) const { onPaste } = editor editor.onPaste = (event) => { const { clipboardData, type } = event if (!clipboardData || !editor.selection) return onPaste(event) const { text, fragment, html, files } = parseDataTransfer(clipboardData) const isPasteText = type === 'pasteText' if (!isPasteText && (fragment.length > 0 || files.length > 0)) { return onPaste(event) } if (Range.isExpanded(editor.selection)) { Transforms.delete(editor) } const anchor = Range.start(editor.selection) onPaste(event) // check markdown syntax if (checkMarkdownSyntax(text, html) && editor.selection) { const focus = Range.end(editor.selection) Promise.resolve().then(() => { const madst = MarkdownDeserializer.toMdastWithEditor(editor, text) const content = MarkdownDeserializer.transformWithEditor(editor, madst)
editor.selection = {
anchor,
focus,
}
editor.insertFragment(content)
})
}
}
return () => {
editor.onPaste = onPaste
}
}, [editor])
//从text获取内容 useIsomorphicLayoutEffect(() => { // 获取初始值 setTimeout(() => { const textw = document.querySelector('#text'); const contentww = textw ? textw.innerHTML : '';
const madstw = MarkdownDeserializer.toMdastWithEditor(editor, contentww)
const contentw = MarkdownDeserializer.transformWithEditor(editor, madstw)
// 设置初始值
if (contentw && contentw.length > 0) {
setInitialValue(contentw as { type: string; children: { text: string }[] }[]);
} else {
setInitialValue([{ type: 'paragraph', children: [{ text: '🤣' }] }]);
}
setIsFetching(false);
}, 200);
}, []);
useContextMenuEffect(() => { ContextMenu.setItems(editor, createContextMenuItems(editor)) }, editor)
useToolbarEffect(() => { Toolbar.setItems(editor, createToolbarItems(editor)) }, editor)
useInlineToolbarEffect(() => { InlineToolbar.setItems(editor, createInlineToolbarItems(editor)) }, editor)
if (isFetching) { return
return ( <> <EditableProvider editor={editor} value={initialValue || []}
</> ) }
大佬,我是这样获取的,只能获取到MD格式。 我不知道怎么添加让它也支持获取到html格式。 现在的编辑器没有报任何错误 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
slatejs
的数据保存都麻了。🙌