You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止ProseMirror中清空title节点后section内容自动上移?

解决ProseMirror中清空title节点后section内容上移的问题

自定义Schema(简化版)

const schema = new Schema({
  nodes: {
    doc: {content: 'title section+'},
    title: {
      content: 'text*',
      marks: "",
      isolating: true,
      toDOM() { return ["span", {class: "document-title"}, 0] },
      parseDOM: [{tag: "span.document-title"}]
    },
    section: {
      group: 'section',
      content: 'block+',
      toDOM() {return ['section', 0]}
    },
    paragraph: {
      content: "inline*",
      group: "block",
      parseDOM: [{ tag: "p" }],
      toDOM() { return ['p', 0]; }
    },
    text: {
      group: 'inline',
      inline: true
    }
  }
})

文档结构

My document title <-- 位于span.document-title内
My document body <-- 位于section内

对应的HTML结构:

<span class="document-title">My document title</span>
<section>My document body</section>

问题描述

清空title节点的所有内容后,<section>内的内容会自动上移,导致title节点的内容变成"My document body",这不符合预期。需要title节点作为独立区域,编辑操作不影响section内的内容。

原本以为给title节点设置isolating: true可以实现该效果,因为ProseMirror官方文档说明:

启用后,此类节点的两侧会被视为边界,常规编辑操作(如退格或提升)无法跨越。

但该设置没有起到预期作用。

原因分析

isolating: true确实会阻止退格、提升等编辑操作跨越节点边界,但问题核心是当title节点内容为空时,编辑器的节点合并逻辑被触发。由于title的content定义为text*(允许空内容),编辑器会认为空的title节点可以被“合并”到相邻的section节点中,从而导致内容移位。

解决方案

1. 强制title节点始终保留存在性

修改title节点的定义,添加empty()方法让ProseMirror认为它永远不能被视为空节点,阻止合并逻辑触发:

title: {
  content: 'text*',
  marks: "",
  isolating: true,
  toDOM() { return ["span", {class: "document-title"}, 0] },
  parseDOM: [{tag: "span.document-title"}],
  // 强制title节点即使无内容也保持存在
  empty() { return false; }
}

2. 自定义按键拦截规则

通过编辑器插件监听退格操作,当title节点为空时阻止退格,避免内容被拉进title区域:

const preventContentShift = new Plugin({
  props: {
    handleKeyDown(view, event) {
      const { state } = view;
      const { $from } = state.selection;
      // 当在title节点内且内容为空时,拦截退格键
      if ($from.parent.type.name === 'title' && $from.parent.textContent === '' && event.key === 'Backspace') {
        return true;
      }
      return false;
    }
  }
});

// 初始化编辑器时加载插件
new EditorView(document.querySelector('#editor'), {
  state: EditorState.create({
    schema,
    plugins: [preventContentShift]
  })
});

3. 将title改为块级DOM元素(可选)

把title的DOM从行内span改为块级元素(如div),减少编辑器对相邻节点的合并倾向:

title: {
  content: 'text*',
  marks: "",
  isolating: true,
  toDOM() { return ["div", {class: "document-title"}, 0] },
  parseDOM: [{tag: "div.document-title"}],
  empty() { return false; }
}

内容的提问来源于stack exchange,提问作者Kinglui11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:15:29