feat(editor): 添加支持服务端渲染的编辑器组件
parent
94ba3bae4a
commit
cd9fce74b5
@ -0,0 +1,69 @@
|
||||
'use client';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import type { Editor as ToastEditor } from '@toast-ui/react-editor';
|
||||
import '@toast-ui/editor/dist/toastui-editor.css';
|
||||
import { isSSR } from '@/utils/is';
|
||||
|
||||
interface EditorSectionProps {
|
||||
initialContent?: string;
|
||||
}
|
||||
|
||||
// 创建一个 Viewer 组件用于服务端渲染
|
||||
const EditorViewer: React.FC<{ content: string }> = ({ content }) => {
|
||||
const viewerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSSR && viewerRef.current) {
|
||||
// 在客户端激活时,动态加载 Viewer 并渲染内容
|
||||
import('@toast-ui/editor/dist/toastui-editor-viewer').then((module) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const { Viewer } = module;
|
||||
new Viewer({
|
||||
el: viewerRef.current!,
|
||||
initialValue: content || ''
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error('Failed to load Toast UI Viewer:', error);
|
||||
});
|
||||
}
|
||||
}, [content]);
|
||||
|
||||
// 服务端直接渲染 HTML 内容
|
||||
return <div ref={viewerRef} dangerouslySetInnerHTML={{ __html: content || '' }} />;
|
||||
};
|
||||
|
||||
export default function EditorSection({ initialContent }: EditorSectionProps) {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const editorRef = useRef<typeof ToastEditor | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSSR) {
|
||||
setIsClient(true);
|
||||
|
||||
// 动态导入编辑器组件
|
||||
import('@toast-ui/react-editor').then((module) => {
|
||||
editorRef.current = module.Editor;
|
||||
}).catch((error) => {
|
||||
console.error('Failed to load Toast UI Editor:', error);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 在服务端或组件未加载完成时,使用 Viewer 模式显示内容
|
||||
if (!isClient || !editorRef.current) {
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<EditorViewer content={initialContent || ''} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const DynamicEditor = editorRef.current;
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<DynamicEditor initialValue={initialContent} initialEditType="markdown" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue