From bcab2fc2804bbeb22ef712b04ddeb8718bdaeb16 Mon Sep 17 00:00:00 2001 From: seaHi Date: Wed, 23 Sep 2026 10:06:05 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=B0=86=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=8F=92=E4=BB=B6=E4=BB=8E=20ViewPlugin=20?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=B8=BA=20StateField=20=E4=BB=A5=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/editor/imagePreviewPlugin.ts | 86 +++++++++++++--------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/src/lib/editor/imagePreviewPlugin.ts b/src/lib/editor/imagePreviewPlugin.ts index 2af91c5..5bd6739 100644 --- a/src/lib/editor/imagePreviewPlugin.ts +++ b/src/lib/editor/imagePreviewPlugin.ts @@ -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 { StateField, type Transaction, type EditorState, Range } from '@codemirror/state'; import { syntaxTree } from '@codemirror/language'; -import { Range } from '@codemirror/state'; class ImagePreviewWidget extends WidgetType { constructor(readonly url: string) { @@ -35,57 +35,51 @@ class ImagePreviewWidget extends WidgetType { } } -function getImageDecorations(view: EditorView) { + +function getImageDecorationsForState(state: EditorState) { const widgets: Range[] = []; - const { state } = view; - for (const { from, to } of view.visibleRanges) { - syntaxTree(state).iterate({ - from, - to, - enter: (node: { name: string; from: number; to: number; node: { getChild: (type: string) => any } }) => { - if (node.name === 'Image') { - // 查找图片语法中的 URL 节点 - const urlNode = node.node.getChild('URL'); - if (urlNode) { - let url = state.doc.sliceString(urlNode.from, urlNode.to); - // 处理可能的带尖括号的 URL - if (url.startsWith('<') && url.endsWith('>')) { - url = url.slice(1, -1); - } - - const deco = Decoration.widget({ - widget: new ImagePreviewWidget(url), - block: true, // 作为块级元素显示在下方 - side: 1 // 插入在节点之后 - }); - - widgets.push(deco.range(node.to)); + syntaxTree(state).iterate({ + enter: (node: { + name: string; + from: number; + to: number; + node: { getChild: (type: string) => any }; + }) => { + if (node.name === 'Image') { + // 查找图片语法中的 URL 节点 + const urlNode = node.node.getChild('URL'); + if (urlNode) { + let url = state.doc.sliceString(urlNode.from, urlNode.to); + // 处理可能的带尖括号的 URL + if (url.startsWith('<') && url.endsWith('>')) { + url = url.slice(1, -1); } + + const deco = Decoration.widget({ + widget: new ImagePreviewWidget(url), + block: true, // 作为块级元素显示在下方 + side: 1 // 插入在节点之后 + }); + + widgets.push(deco.range(node.to)); } } - }); - } + } + }); return Decoration.set(widgets.sort((a, b) => a.from - b.from)); } -export const imagePreviewPlugin = ViewPlugin.fromClass( - class { - decorations: DecorationSet; - - constructor(view: EditorView) { - this.decorations = getImageDecorations(view); - } - - update(update: ViewUpdate) { - // 文档改变或视口改变时重新计算 - if (update.docChanged || update.viewportChanged) { - this.decorations = getImageDecorations(update.view); - } - } +export const imagePreviewPlugin = StateField.define({ + create(state) { + return getImageDecorationsForState(state); }, - { - decorations: (v) => v.decorations - } -); + update(value, tr: Transaction) { + if (tr.docChanged) { + return getImageDecorationsForState(tr.state); + } + return value; + }, + provide: (f) => EditorView.decorations.from(f) +});