diff --git a/packages/mini-markdown-editor/src/App.tsx b/packages/mini-markdown-editor/src/App.tsx
index 27f96b684d722a8ffc24b54e3b79df834a8f82e4..0560cca30b8726371a50f0f6855d930e5561ce66 100644
--- a/packages/mini-markdown-editor/src/App.tsx
+++ b/packages/mini-markdown-editor/src/App.tsx
@@ -18,7 +18,7 @@ const App: FC = () => {
const handleUpload = async (file: File, callback: Callback) => {
await new Promise((resolve) => {
setTimeout(() => {
- console.log("settimout 上传成功", file);
+ console.log("settimeout 上传成功", file);
resolve({});
}, 1500);
});
@@ -30,7 +30,7 @@ const App: FC = () => {
};
return (
-
+
);
};
diff --git a/packages/mini-markdown-editor/src/EditorWrapper.tsx b/packages/mini-markdown-editor/src/EditorWrapper.tsx
index 497ef07c1dd90c69e196ac106df8ca8a8ad51282..a3b764926e7fead3427c19a61b8a0b65dc4d7885 100644
--- a/packages/mini-markdown-editor/src/EditorWrapper.tsx
+++ b/packages/mini-markdown-editor/src/EditorWrapper.tsx
@@ -11,6 +11,7 @@ import { ConfigProvider } from "@/components/providers/config-provider";
import { HotkeysProvider } from "@/components/providers/hotkeys-provider";
import { GlobalConfig } from "./types/global-config";
import { useToolbarStore } from "./store/toolbar";
+import { useInitSyncScrollStatus } from "./hooks/use-init-sync-scroll-status";
const Container = styled.div`
width: 100%;
@@ -143,6 +144,7 @@ const EditorWrapper: FC = (config) => {
const content = useEditorContentStore((state) => state.content);
const deferredContent = useDeferredValue(content);
const isFullScreen = useToolbarStore((state) => state.isFullScreen);
+ const { isSyncScroll, updateSyncScrollStatus } = useInitSyncScrollStatus();
return (
@@ -155,12 +157,17 @@ const EditorWrapper: FC = (config) => {
{/* 内容区域 */}
- } preview={} />
+ }
+ preview={}
+ />
{/* 底部状态栏 */}
- {config.status ? : null}
+ {config.status ? (
+
+ ) : null}
);
diff --git a/packages/mini-markdown-editor/src/components/Editor/index.tsx b/packages/mini-markdown-editor/src/components/Editor/index.tsx
index 4094e24da31c99db4d7d501b70f7f7ee16d02a45..a48738258565db1ab5cd10961a7c9e57b8399f4d 100644
--- a/packages/mini-markdown-editor/src/components/Editor/index.tsx
+++ b/packages/mini-markdown-editor/src/components/Editor/index.tsx
@@ -6,10 +6,9 @@ import { languages } from "@codemirror/language-data";
import * as events from "@uiw/codemirror-extensions-events";
import { useEditorContentStore } from "@/store/editor";
import { handleEditorScroll } from "@/utils/handle-scroll";
-import { safeLocalStorage } from "@/utils/storage";
-import { EDITOR_CONTENT_KEY, SYNC_SCROLL_STATUS } from "@/common";
import { useEditorShortcuts } from "@/hooks/use-editor-shortcuts";
import { HotkeysContext } from "../providers/hotkeys-provider";
+import { usePersistEditorContent } from "@/hooks/use-persist-editor-content";
const ScrollWrapper = styled.div`
width: 100%;
@@ -38,7 +37,7 @@ const ScrollWrapper = styled.div`
}
`;
-const Editor: FC = () => {
+const Editor: FC<{ isSyncScroll: boolean }> = ({ isSyncScroll }) => {
const {
content,
setContent,
@@ -48,7 +47,6 @@ const Editor: FC = () => {
previewView,
editorView,
} = useEditorContentStore();
- const localStorage = safeLocalStorage();
// ref转发
const editorViewRef = useRef();
// 存储实例
@@ -61,6 +59,8 @@ const Editor: FC = () => {
);
// 监听快捷键
useEditorShortcuts();
+ // 持久化存储内容
+ const { saveContent, getContent } = usePersistEditorContent();
// 处理重加载后的光标位置
useEffect(() => {
@@ -72,6 +72,11 @@ const Editor: FC = () => {
}
}, [editorView]);
+ // 初始化时获取本地存储的内容
+ useEffect(() => {
+ setContent(getContent());
+ }, []);
+
// 编辑器挂载完成后将编辑器示例存储起来
const handleCreate = (view: EditorView) => {
setEditorViewInstance(view);
@@ -81,7 +86,7 @@ const Editor: FC = () => {
// 更新store
setContent(val);
// 本地同步存储
- localStorage.setItem(EDITOR_CONTENT_KEY, val);
+ saveContent(val);
// 更新编辑器实例
setEditorViewInstance(editView.view);
};
@@ -90,7 +95,9 @@ const Editor: FC = () => {
scroll: () => {
if (scrollWrapper !== "editor") return;
const view = editorViewRef.current;
- if (!(view && previewView && localStorage.getItem(SYNC_SCROLL_STATUS) === "true")) return;
+ console.log(view);
+ if (!(view && previewView && isSyncScroll)) return;
+ console.log(isSyncScroll);
handleEditorScroll({ editorView: view, previewView });
},
});
diff --git a/packages/mini-markdown-editor/src/components/Preview/index.tsx b/packages/mini-markdown-editor/src/components/Preview/index.tsx
index da2b98e8d0e28c0e01bc7c785dcc7d889a307bb4..d800918f84095fe5439a90eb948f8bf795e7a549 100644
--- a/packages/mini-markdown-editor/src/components/Preview/index.tsx
+++ b/packages/mini-markdown-editor/src/components/Preview/index.tsx
@@ -1,4 +1,4 @@
-import { FC, useEffect, useRef } from "react";
+import { FC, useEffect, useRef, useCallback } from "react";
import { parseMarkdown, transformHtml } from "@mini-markdown/ast-parser";
import "@/assets/styles/preview.css";
import "highlight.js/styles/atom-one-dark.css";
@@ -6,8 +6,6 @@ import styled from "styled-components";
import { useEditorContentStore } from "@/store/editor";
import { handlePreviewScroll } from "@/utils/handle-scroll";
import React from "react";
-import { safeLocalStorage } from "@/utils/storage";
-import { SYNC_SCROLL_STATUS } from "@/common";
const ScrollWrapper = styled.div`
width: 100%;
@@ -17,45 +15,55 @@ const ScrollWrapper = styled.div`
word-wrap: break-word;
`;
-const Preview: FC<{ content: string }> = ({ content }) => {
- // store
+const Preview: FC<{ content: string; isSyncScroll: boolean }> = ({ content, isSyncScroll }) => {
const { scrollWrapper, setScrollWrapper, setPreviewView, editorView } = useEditorContentStore();
- const localStorage = safeLocalStorage();
+
+ const previewRef = useRef(null);
+
+ // 更新预览视图
+ const updatePreviewView = useCallback(
+ (element: HTMLDivElement | null) => {
+ if (element) {
+ setPreviewView(element);
+ }
+ },
+ [setPreviewView],
+ );
// 渲染 html 节点
const node = React.useMemo(() => {
const ast = parseMarkdown(content);
return transformHtml(ast);
}, [content]);
- const previewRef = useRef(null);
// 更新渲染实例
useEffect(() => {
- if (previewRef.current && node) {
- setPreviewView(previewRef.current);
- }
- }, [node]);
-
- const handleScroll = (e: React.UIEvent) => {
- if (scrollWrapper !== "preview") return;
- const previewView = e.currentTarget;
- if (!(editorView && previewView && localStorage.getItem(SYNC_SCROLL_STATUS) === "true")) return;
- handlePreviewScroll({ previewView, editorView });
- };
-
- const handleMoseEnter = () => {
+ updatePreviewView(previewRef.current);
+ }, [updatePreviewView, node]);
+
+ const handleScroll = useCallback(
+ (e: React.UIEvent) => {
+ if (scrollWrapper !== "preview") return;
+ const previewView = e.currentTarget;
+ if (!(editorView && previewView && isSyncScroll)) return;
+ handlePreviewScroll({ previewView, editorView });
+ },
+ [scrollWrapper, editorView, isSyncScroll],
+ );
+
+ const handleMouseEnter = useCallback(() => {
setScrollWrapper("preview");
- };
+ }, [setScrollWrapper]);
return (
- // className='markdown-editor-preview' 重置样式的节点
+ />
);
};
-export default Preview;
+
+export default React.memo(Preview);
diff --git a/packages/mini-markdown-editor/src/components/Status/index.tsx b/packages/mini-markdown-editor/src/components/Status/index.tsx
index dec3dbc2d7661f5aac2936b0ab34c0df17c7b0ea..4f5e38b389bd6a9710907a355348bfc17375191d 100644
--- a/packages/mini-markdown-editor/src/components/Status/index.tsx
+++ b/packages/mini-markdown-editor/src/components/Status/index.tsx
@@ -1,10 +1,8 @@
-import { FC, useEffect, useMemo, useState } from "react";
+import { FC, useMemo } from "react";
import styled from "styled-components";
import { useEditorContentStore } from "@/store/editor";
import { Checkbox } from "antd";
import type { CheckboxProps } from "antd";
-import { SYNC_SCROLL_STATUS } from "@/common";
-import { safeLocalStorage } from "@/utils/storage";
const StatusWrapper = styled.div`
width: 100%;
@@ -38,34 +36,26 @@ const StatusWrapper = styled.div`
}
`;
-const Status: FC = () => {
+const Status: FC<{ isSyncScroll: boolean; updateSyncScrollStatus: (val: boolean) => void }> = ({
+ isSyncScroll,
+ updateSyncScrollStatus,
+}) => {
const content = useEditorContentStore((state) => state.content);
- const localStorage = safeLocalStorage();
- const [syncScroll, setSyncScroll] = useState();
const contentNum = useMemo(() => {
return content.replace(/[\s\n]/g, "").length;
}, [content]);
- // 初始化时从 localStorage 读取状态
- useEffect(() => {
- const savedStatus = localStorage.getItem(SYNC_SCROLL_STATUS);
- //! 明确转换为布尔值
- const initialStatus = savedStatus === null ? true : savedStatus === "true";
- setSyncScroll(initialStatus);
- }, [localStorage]);
-
// 状态改变处理函数
const handleSyncScrollChange: CheckboxProps["onChange"] = (e) => {
- setSyncScroll(e.target.checked);
- localStorage.setItem(SYNC_SCROLL_STATUS, String(e.target.checked));
+ updateSyncScrollStatus(e.target.checked);
};
return (
字数: {contentNum}
-
+
同步滚动
滚动到顶部
diff --git a/packages/mini-markdown-editor/src/hooks/use-init-sync-scroll-status.ts b/packages/mini-markdown-editor/src/hooks/use-init-sync-scroll-status.ts
new file mode 100644
index 0000000000000000000000000000000000000000..be6bec43993404bd445ac44c3ac59f11bd093afe
--- /dev/null
+++ b/packages/mini-markdown-editor/src/hooks/use-init-sync-scroll-status.ts
@@ -0,0 +1,32 @@
+import { SYNC_SCROLL_STATUS } from "@/common";
+import { safeLocalStorage } from "@/utils/storage";
+import { useEffect, useState } from "react";
+
+export const useInitSyncScrollStatus = () => {
+ const localStorage = safeLocalStorage();
+ const [isSyncScroll, setIsSyncScroll] = useState(() => {
+ const status = localStorage.getItem(SYNC_SCROLL_STATUS);
+ return status === null ? true : status !== "false";
+ });
+
+ // 初始化同步滚动状态
+ const initSyncScrollStatus = () => {
+ const status = localStorage.getItem(SYNC_SCROLL_STATUS);
+ if (status === null) {
+ localStorage.setItem(SYNC_SCROLL_STATUS, "true");
+ }
+ };
+
+ const updateSyncScrollStatus = (status: boolean) => {
+ localStorage.setItem(SYNC_SCROLL_STATUS, String(status));
+ //! 更新状态
+ setIsSyncScroll(status);
+ };
+
+ // 初始化同步滚动状态
+ useEffect(() => {
+ initSyncScrollStatus();
+ }, []);
+
+ return { isSyncScroll, updateSyncScrollStatus };
+};
diff --git a/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts b/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts
new file mode 100644
index 0000000000000000000000000000000000000000..085c12d9827f055e9e2655042bb0229dea45a111
--- /dev/null
+++ b/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts
@@ -0,0 +1,24 @@
+import { EDITOR_CONTENT_KEY } from "@/common";
+import { ConfigContext } from "@/components/providers/config-provider";
+import { safeLocalStorage } from "@/utils/storage";
+import { useContext } from "react";
+
+export const usePersistEditorContent = () => {
+ const localStorage = safeLocalStorage();
+ const { local } = useContext(ConfigContext);
+
+ // 保存内容
+ const saveContent = (content: string) => {
+ if (local) {
+ localStorage.setItem(EDITOR_CONTENT_KEY, content);
+ }
+ };
+
+ // 获取内容
+ const getContent = (): string => {
+ if (!local) return "";
+ return localStorage.getItem(EDITOR_CONTENT_KEY) ?? "";
+ };
+
+ return { saveContent, getContent };
+};
diff --git a/packages/mini-markdown-editor/src/store/editor.ts b/packages/mini-markdown-editor/src/store/editor.ts
index ca08928a554a4efa401e4a5b109e9d251cf8a38d..43dae0b19da8defdb87d848062930e7a3077fd94 100644
--- a/packages/mini-markdown-editor/src/store/editor.ts
+++ b/packages/mini-markdown-editor/src/store/editor.ts
@@ -1,7 +1,5 @@
import { create } from "zustand";
import type { EditorView } from "@codemirror/view";
-import { safeLocalStorage } from "@/utils/storage";
-import { EDITOR_CONTENT_KEY } from "@/common";
interface EditorContentStoreType {
content: string;
@@ -16,11 +14,9 @@ interface EditorContentStoreType {
setPreviewView: (view: HTMLElement | null) => void;
}
-const localStorage = safeLocalStorage();
-
// 编辑器内容状态
const useEditorContentStore = create((set) => ({
- content: localStorage.getItem(EDITOR_CONTENT_KEY) || "",
+ content: "",
setContent: (content: string) => set({ content }),
scrollWrapper: "",
setScrollWrapper: (scrollWrapper: string) => set({ scrollWrapper }),