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

如何在Draft.js中实现分段固定且不可编辑删除的只读标题?

我之前在项目里刚好折腾过类似的需求,Draft.js要实现这种分Section且Header只读不可删的功能,得结合自定义Block和变更拦截来搞,一步步给你拆解:

在Draft.js中实现只读Section Header的方案

核心思路是:把每个Section Header标记为特殊的不可编辑Block类型,然后通过自定义渲染、变更拦截、光标限制这几层,彻底锁死Header的修改/删除操作。

1. 给Header注册专属Block类型

首先得让Draft.js识别哪些是Header,我们可以给Header创建一个专属的Block类型(比如叫'section-header'),和普通的可编辑段落区分开。初始化编辑器内容时,把每个Section的Header作为这个类型的Block插入:

import { EditorState, ContentBlock, ContentState } from 'draft-js';

// 初始化带Section的编辑器内容
const initialContentBlocks = [
  // History Header + 内容
  new ContentBlock({
    key: 'header-history',
    type: 'section-header',
    text: 'History',
    characterList: Array('History'.length).fill({}),
  }),
  new ContentBlock({
    key: 'content-history',
    type: 'unstyled',
    text: '此处为文本...',
    characterList: Array('此处为文本...'.length).fill({}),
  }),
  // Examination Header + 内容
  new ContentBlock({
    key: 'header-examination',
    type: 'section-header',
    text: 'Examination',
    characterList: Array('Examination'.length).fill({}),
  }),
  new ContentBlock({
    key: 'content-examination',
    type: 'unstyled',
    text: '此处为文本...',
    characterList: Array('此处为文本...'.length).fill({}),
  }),
];

const initialEditorState = EditorState.createWithContent(
  ContentState.createFromBlockArray(initialContentBlocks)
);

2. 自定义Header的渲染组件

接下来要告诉Draft.js怎么渲染这个'section-header'类型的Block——直接渲染成不可编辑的元素,还要加样式区分,同时阻止用户选中它:

const CustomBlockRenderer = (props) => {
  const { block } = props;
  if (block.getType() === 'section-header') {
    return (
      <div 
        style={{ 
          fontSize: '1.2rem', 
          fontWeight: 'bold', 
          margin: '1rem 0 0.5rem',
          color: '#2c3e50',
          background: '#f8f9fa',
          padding: '0.3rem 0.8rem',
          borderRadius: '4px'
        }}
        contentEditable={false}
        pointerEvents="none" // 彻底阻止点击/选中
      >
        {block.getText()}
      </div>
    );
  }
  // 普通文本Block用默认渲染逻辑
  return null;
};

// 把这个渲染函数传给Editor组件
<Editor
  editorState={editorState}
  onChange={handleEditorChange}
  blockRendererFn={CustomBlockRenderer}
/>

3. 拦截非法变更,禁止修改/删除Header

光渲染只读还不够,用户可能通过Backspace删除Header、或者粘贴内容覆盖Header,所以必须在onChange回调里拦截这类操作:

const handleEditorChange = (newEditorState) => {
  const oldContent = editorState.getCurrentContent();
  const newContent = newEditorState.getCurrentContent();

  // 检查有没有Header被修改(内容/类型变了)
  const hasHeaderModified = oldContent.getBlocksAsArray().some((oldBlock, idx) => {
    const newBlock = newContent.getBlocksAsArray()[idx];
    if (!newBlock) return true; // 原Header被删除了
    if (oldBlock.getType() === 'section-header') {
      return oldBlock.getText() !== newBlock.getText() || oldBlock.getType() !== newBlock.getType();
    }
    return false;
  });

  // 检查有没有Header被整段删除
  const oldHeaderCount = oldContent.getBlocksAsArray().filter(b => b.getType() === 'section-header').length;
  const newHeaderCount = newContent.getBlocksAsArray().filter(b => b.getType() === 'section-header').length;
  const hasHeaderRemoved = oldHeaderCount > newHeaderCount;

  // 只要有非法操作,就拒绝这次变更
  if (hasHeaderModified || hasHeaderRemoved) {
    return;
  }

  // 合法操作才更新编辑器状态
  setEditorState(newEditorState);
};

4. 额外优化:不让光标进入Header

最后再加一层保险——阻止光标定位到Header里,彻底断了用户编辑Header的可能:

// 阻止在Header里输入内容
const handleBeforeInput = (chars, editorState) => {
  const selectedBlock = editorState.getCurrentContent().getBlockForKey(
    editorState.getSelection().getStartKey()
  );
  if (selectedBlock.getType() === 'section-header') {
    return 'handled'; // 告诉Draft.js我们处理了这个输入,不用执行默认逻辑
  }
  return 'not-handled';
};

// 阻止在Header里执行编辑快捷键(比如复制/剪切)
const handleKeyCommand = (command, editorState) => {
  const selectedBlock = editorState.getCurrentContent().getBlockForKey(
    editorState.getSelection().getStartKey()
  );
  if (selectedBlock.getType() === 'section-header') {
    return 'handled';
  }
  return 'not-handled';
};

// 把这两个回调加到Editor组件
<Editor
  editorState={editorState}
  onChange={handleEditorChange}
  blockRendererFn={CustomBlockRenderer}
  onBeforeInput={handleBeforeInput}
  handleKeyCommand={handleKeyCommand}
/>

这样一套组合拳下来,Section Header就彻底变成了只读、不可删除、用户碰都碰不到的固定元素,而每个Section里的内容则可以正常编辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:26:36