Monaco编辑器报错:lineNumber值非法,动态修改内容时如何处理装饰?
Monaco编辑器0.38版本装饰报错解决方案
问题原因
从0.30升级到0.38后,Monaco的装饰管理逻辑有调整,当动态修改内容导致行数减少时,若装饰操作与内容更新的时序不当,或使用的装饰API未适配新版本的模型同步逻辑,就会出现非法行号的报错——即使调用了清空装饰的代码,也可能因为旧装饰未完全清理、新装饰引用了已不存在的行号而触发错误。
正确的装饰管理方式
1. 改用createDecorationsCollection管理装饰
放弃deltaDecorations,使用createDecorationsCollection创建可观察的装饰集合,它能自动适配模型内容的变化,避免手动管理装饰ID的时序问题。
初始化装饰集合
// 类内属性声明 private decorationCollection: monaco.editor.IEditorDecorationsCollection | null = null; // 编辑器初始化完成后创建集合 this.decorationCollection = this.editor!.createDecorationsCollection();
清空装饰
this.decorationCollection!.set([]);
更新内容并添加新装饰
// 步骤1:先清空现有装饰 this.decorationCollection!.set([]); // 步骤2:更新编辑器内容 this.editor!.setValue(newContent); // 步骤3:确保内容更新后,再添加新装饰(校验行号合法性) const model = this.editor!.getModel(); if (!model) return; const maxLine = model.getLineCount(); // 仅当错误行号在合法范围内时添加装饰 if (errorLine <= maxLine && errorLine >= 1) { const newDecorations: monaco.editor.IModelDeltaDecoration[] = [ { range: new monaco.Range(errorLine, 1, errorLine, model.getLineMaxColumn(errorLine)), options: { className: 'custom-error-decoration', // 其他装饰配置 } } ]; this.decorationCollection!.set(newDecorations); }
2. 若坚持使用deltaDecorations
需严格保证时序和行号合法性:
- 每次更新内容前,必须调用
deltaDecorations清空所有装饰,且确保返回的新装饰ID被正确保存。 - 内容更新完成后,重新计算装饰的行号(必须小于等于当前模型的总行数),再调用
deltaDecorations添加新装饰。
// 清空装饰 this.decorations = this.editor!.deltaDecorations(this.decorations, []); // 更新内容 this.editor!.setValue(newContent); // 添加新装饰前校验行号 const model = this.editor!.getModel(); if (!model) return; const maxLine = model.getLineCount(); if (errorLine > maxLine) return; const newDecorations = [ { range: new monaco.Range(errorLine, 1, errorLine, model.getLineMaxColumn(errorLine)), options: { className: 'error-line' } } ]; this.decorations = this.editor!.deltaDecorations(this.decorations, newDecorations);
关键注意事项
- 任何时候添加装饰前,都必须校验目标行号是否在当前模型的有效行数范围内(
1 <= lineNumber <= model.getLineCount())。 - 不要同时混用
deltaDecorations和createDecorationsCollection,避免装饰管理冲突。 - 若遇到异步渲染导致的延迟,可通过
editor.onDidChangeModelContent事件监听内容更新完成,再触发装饰添加:
this.editor!.onDidChangeModelContent(() => { // 内容更新完成后执行装饰逻辑 this.updateDecorations(); });
内容的提问来源于stack exchange,提问作者Simon H
相关产品推荐
相关产品推荐

