refactor: 将图片预览插件从 ViewPlugin 重构为 StateField 以优化性能
continuous-integration/drone/push Build is failing

This commit is contained in:
seahi committed 2026-09-23 10:06:05 +08:00
1 parent aa4a4236ed
commit bcab2fc280
1 file changed
+21 -27
+21 -27
View File
@@ -1,7 +1,7 @@
import { WidgetType, EditorView, ViewPlugin, Decoration, ViewUpdate } from '@codemirror/view'; import { WidgetType, EditorView, Decoration } from '@codemirror/view';
import type { DecorationSet } from '@codemirror/view'; import type { DecorationSet } from '@codemirror/view';
import { StateField, type Transaction, type EditorState, Range } from '@codemirror/state';
import { syntaxTree } from '@codemirror/language'; import { syntaxTree } from '@codemirror/language';
import { Range } from '@codemirror/state';
class ImagePreviewWidget extends WidgetType { class ImagePreviewWidget extends WidgetType {
constructor(readonly url: string) { constructor(readonly url: string) {
@@ -35,15 +35,17 @@ class ImagePreviewWidget extends WidgetType {
} }
} }
function getImageDecorations(view: EditorView) {
const widgets: Range<Decoration>[] = [];
const { state } = view;
for (const { from, to } of view.visibleRanges) { function getImageDecorationsForState(state: EditorState) {
const widgets: Range<Decoration>[] = [];
syntaxTree(state).iterate({ syntaxTree(state).iterate({
from, enter: (node: {
to, name: string;
enter: (node: { name: string; from: number; to: number; node: { getChild: (type: string) => any } }) => { from: number;
to: number;
node: { getChild: (type: string) => any };
}) => {
if (node.name === 'Image') { if (node.name === 'Image') {
// 查找图片语法中的 URL 节点 // 查找图片语法中的 URL 节点
const urlNode = node.node.getChild('URL'); const urlNode = node.node.getChild('URL');
@@ -65,27 +67,19 @@ function getImageDecorations(view: EditorView) {
} }
} }
}); });
}
return Decoration.set(widgets.sort((a, b) => a.from - b.from)); return Decoration.set(widgets.sort((a, b) => a.from - b.from));
} }
export const imagePreviewPlugin = ViewPlugin.fromClass( export const imagePreviewPlugin = StateField.define<DecorationSet>({
class { create(state) {
decorations: DecorationSet; return getImageDecorationsForState(state);
constructor(view: EditorView) {
this.decorations = getImageDecorations(view);
}
update(update: ViewUpdate) {
// 文档改变或视口改变时重新计算
if (update.docChanged || update.viewportChanged) {
this.decorations = getImageDecorations(update.view);
}
}
}, },
{ update(value, tr: Transaction) {
decorations: (v) => v.decorations if (tr.docChanged) {
return getImageDecorationsForState(tr.state);
} }
); return value;
},
provide: (f) => EditorView.decorations.from(f)
});