优化模式切换功能
This commit is contained in:
@@ -89,6 +89,61 @@ const isEditingEmptyDocument = computed(
|
||||
() => editingBlockId.value === EMPTY_BLOCK_ID,
|
||||
);
|
||||
let textareaResizeFrame: number | null = null;
|
||||
let modeScrollRestoreFrame: number | null = null;
|
||||
|
||||
interface ScrollSnapshot {
|
||||
ratio: number;
|
||||
}
|
||||
|
||||
function getScrollableDistance(el: HTMLElement) {
|
||||
return Math.max(0, el.scrollHeight - el.clientHeight);
|
||||
}
|
||||
|
||||
function captureScrollSnapshot(): ScrollSnapshot | null {
|
||||
const el = scrollRef.value;
|
||||
if (!el) return null;
|
||||
|
||||
const maxScrollTop = getScrollableDistance(el);
|
||||
return {
|
||||
ratio: maxScrollTop > 0 ? el.scrollTop / maxScrollTop : 0,
|
||||
};
|
||||
}
|
||||
|
||||
function restoreScrollSnapshot(snapshot: ScrollSnapshot | null) {
|
||||
const el = scrollRef.value;
|
||||
if (!el || !snapshot) return;
|
||||
|
||||
const maxScrollTop = getScrollableDistance(el);
|
||||
el.scrollTop = maxScrollTop * snapshot.ratio;
|
||||
}
|
||||
|
||||
function restoreScrollAfterModeChange(
|
||||
snapshot: ScrollSnapshot | null,
|
||||
mode: DocumentMode,
|
||||
) {
|
||||
if (!snapshot) return;
|
||||
|
||||
if (modeScrollRestoreFrame !== null) {
|
||||
cancelAnimationFrame(modeScrollRestoreFrame);
|
||||
modeScrollRestoreFrame = null;
|
||||
}
|
||||
|
||||
void nextTick(() => {
|
||||
if (mode === "edit" && editorTextareaRef.value) {
|
||||
resizeTextarea(editorTextareaRef.value);
|
||||
}
|
||||
|
||||
restoreScrollSnapshot(snapshot);
|
||||
|
||||
modeScrollRestoreFrame = requestAnimationFrame(() => {
|
||||
modeScrollRestoreFrame = null;
|
||||
if (mode === "edit" && editorTextareaRef.value) {
|
||||
resizeTextarea(editorTextareaRef.value);
|
||||
}
|
||||
restoreScrollSnapshot(snapshot);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncRenderedState(md: string, mode = activeDocumentMode.value) {
|
||||
if (mode === "preview") {
|
||||
@@ -455,6 +510,7 @@ function flushPendingChanges(): string | undefined {
|
||||
}
|
||||
|
||||
watch(activeDocumentMode, (mode, oldMode) => {
|
||||
const scrollSnapshot = captureScrollSnapshot();
|
||||
let committedValue: string | undefined;
|
||||
if (oldMode === "mixed" && mode !== "mixed" && editingBlockId.value) {
|
||||
committedValue = finalizeBlockEdit();
|
||||
@@ -465,12 +521,17 @@ watch(activeDocumentMode, (mode, oldMode) => {
|
||||
if (mode === "edit") {
|
||||
void nextTick(scheduleEditorTextareaResize);
|
||||
}
|
||||
|
||||
restoreScrollAfterModeChange(scrollSnapshot, mode);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (textareaResizeFrame !== null) {
|
||||
cancelAnimationFrame(textareaResizeFrame);
|
||||
}
|
||||
if (modeScrollRestoreFrame !== null) {
|
||||
cancelAnimationFrame(modeScrollRestoreFrame);
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
|
||||
Reference in New Issue
Block a user