如何在Lexical编辑器中实现不可删改内容以支持填空场景?
场景背景
需要实现长文本中的填空功能,类似语言学习教材里的动词时态填空——仅填空区域可编辑,其余文本固定不可修改。
最初考虑用独立输入框对应每个填空,但跨多行输入时,要么无法查看完整文本,要么用多行文本域会导致排版混乱。之前用DraftJs实现,但在Android端测试出问题,现在转用Lexical(看中其跨平台兼容性)。
解决方案实现方案
方法一:自定义不可编辑节点(推荐)
Lexical支持创建自定义节点,你可以把固定文本封装成不可编辑的自定义节点,填空区域用默认的可编辑文本节点:
- 创建继承自
TextNode的自定义节点,重写isEditable()方法返回false,直接阻止对该节点的编辑操作:
class FixedTextNode extends TextNode { static getType() { return 'fixed-text'; } isEditable() { return false; } clone() { return new FixedTextNode(this.__text, this.__key); } }
- 把这个自定义节点注册到编辑器配置里:
const config = { nodes: [FixedTextNode], // 其他编辑器配置 };
- 初始化内容时,用
FixedTextNode包裹固定文本,填空区域用普通TextNode即可:
editor.update(() => { const root = $getRoot(); root.append( $createFixedTextNode('When I arrived at the station, the train '), $createTextNode(''), // 这里是可编辑的填空区域 $createFixedTextNode(' already.') ); });
这种方式符合Lexical的设计逻辑,不需要额外拦截状态,框架会直接保护不可编辑节点。
方法二:拦截编辑器状态变更
如果需要更细粒度的校验(比如确认固定文本未被篡改),可以通过updateListener拦截状态变更,不合法就回退到之前的状态:
- 注册状态更新监听器:
editor.registerUpdateListener(({editorState, prevEditorState}) => { const isValid = checkFixedText(editorState); if (!isValid) { editor.setEditorState(prevEditorState); } });
- 实现校验函数,遍历节点树检查固定文本是否符合预期:
function checkFixedText(editorState) { let isValid = true; editorState.read(() => { const root = $getRoot(); root.forEach(node => { // 假设固定文本节点类型是'fixed-text',检查内容是否正确 if (node.getType() === 'fixed-text' && node.getTextContent() !== '预期的固定文本内容') { isValid = false; } }); }); return isValid; }
注意:这种方式需要维护固定文本的预期值,频繁回退可能影响用户体验,优先选自定义节点方案。
额外提示
- 可以给填空区域加下划线样式,通过给可编辑节点加CSS类或者自定义装饰节点实现,让用户更容易识别。
- 测试时重点验证Android端的操作,确保不可编辑区域不会被误修改。
内容的提问来源于stack exchange,提问作者Andres
相关产品推荐
相关产品推荐

