如何为Draft.js中大量独立字符批量应用自定义行内样式
Draft.js自定义语法高亮批量样式设置方案
你要实现的单字符粒度自定义样式完全可以通过直接操作ContentBlock的characterList实现,不需要逐字符调用RichUtils.toggleInlineStyle,性能足以支撑IDE级别的语法高亮需求。
核心原理
Draft.js的每个ContentBlock都维护了一个characterList属性(就是你在文档里看到的样式数组),每个位置对应一个Immutable.OrderedSet,存储当前字符的所有inline样式。你只需要按自己的语法高亮规则批量生成这个List,替换原有属性即可。
注:Draft.js依赖Immutable.js的
OrderedSet实现样式存储,相关API可以直接查阅Immutable.js官方定义,Draft文档没有单独说明。
实现步骤
- 首先配置自定义样式映射,传入Editor组件的
customStyleMap属性:
const customStyleMap = { red: { color: '#ff0000' }, keyword: { color: '#7928ca', fontWeight: 'bold' }, string: { color: '#008000' }, // 其他你需要的自定义样式 }
- 替换你现有的onChange逻辑,批量处理样式:
import { OrderedSet } from 'immutable'; import { EditorState, ContentState, CharacterMetadata } from 'draft-js'; const onChange = (newEditorState) => { const contentState = newEditorState.getCurrentContent(); const currentSelection = newEditorState.getSelection(); // 遍历所有block,批量更新样式 const newBlockMap = contentState.getBlockMap().map(block => { const blockText = block.getText(); // 这里替换成你自己的语法高亮逻辑,返回每个字符对应的样式数组 // 示例:假设第0-2个字符要加red样式,第3-5个加keyword样式 const charMetadataList = []; for (let i = 0; i < blockText.length; i++) { let styles = OrderedSet(); // 你的高亮判断逻辑 if (i < 3) { styles = styles.add('red'); } else if (i < 6) { styles = styles.add('keyword'); } charMetadataList.push(CharacterMetadata.create({ style: styles })); } // 替换block的characterList return block.set('characterList', Immutable.List(charMetadataList)); }); // 生成新的contentState和editorState,保留原有光标位置 const newContentState = ContentState.createFromBlockArray(newBlockMap.toArray()); const finalEditorState = EditorState.push( newEditorState, newContentState, 'change-inline-style' ); const editorStateWithSelection = EditorState.forceSelection(finalEditorState, currentSelection); setEditorState(editorStateWithSelection); }
性能优化建议
- 语法分词可以做防抖处理,只有用户停止输入100-200ms后再重新计算样式,避免输入卡顿
- 缓存已经分词过的block,只有block文本发生变化时才重新计算样式,不需要每次onChange都全量遍历
内容的提问来源于stack exchange,提问作者dontfknow
相关产品推荐
相关产品推荐

