如何实现两个Monaco编辑器之间的行高度视觉匹配?
实现两个Monaco编辑器行高同步匹配的方案
核心逻辑和官方diff模式的实现思路一致,通过同步每一行的实际渲染高度即可实现,具体操作步骤如下:
- 第一步:统一编辑器基础排版配置
首先要保证两个编辑器的基础排版参数完全对齐,避免出现基础行高偏差:
const sharedConfig = { lineHeight: 20, // 固定基础单行行高 wordWrap: 'on', // 折行规则保持一致,也可按业务需求单独配置,不影响行高同步逻辑 fontSize: 14, fontFamily: 'Consolas, "Courier New", monospace', scrollBeyondLastLine: false, // 其他会影响行排版的参数都要统一,比如行内边距、字重等 } const editorA = monaco.editor.create(document.getElementById('editor-a'), sharedConfig) const editorB = monaco.editor.create(document.getElementById('editor-b'), sharedConfig)
- 第二步:实现行高同步核心函数
使用Monaco官方提供的changeViewZonesAPI(diff编辑器同步行高的核心接口),给高度不足的行插入对应的空白填充区域,强制行高对齐:
function syncLineHeights(sourceEditor, targetEditor) { const maxSyncLine = Math.min(sourceEditor.getModel().getLineCount(), targetEditor.getModel().getLineCount()) const fillZones = [] for (let line = 1; line <= maxSyncLine; line++) { // 取源编辑器当前行的实际渲染高度(包含折行后的总高度) const sourceActualHeight = sourceEditor.getLineHeight(line) // 取目标编辑器当前行的原生高度 const targetActualHeight = targetEditor.getLineHeight(line) // 高度不一致时计算差值,插入填充区域 if (sourceActualHeight > targetActualHeight) { const diff = sourceActualHeight - targetActualHeight fillZones.push({ afterLineNumber: line - 1, heightInPx: diff, domNode: document.createElement('div'), suppressMouseDown: true }) } } // 替换目标编辑器的所有填充区域,避免重复添加 targetEditor.changeViewZones(accessor => { accessor.clear() fillZones.forEach(zone => accessor.addZone(zone)) }) }
- 第三步:绑定同步触发事件
所有会导致行高变化的场景都要触发双向同步:
const biDirectionSync = () => { syncLineHeights(editorA, editorB) syncLineHeights(editorB, editorA) } // 内容变更时同步 editorA.onDidChangeModelContent(biDirectionSync) editorB.onDidChangeModelContent(biDirectionSync) // 编辑器尺寸变化时同步 editorA.onDidLayoutChange(biDirectionSync) editorB.onDidLayoutChange(biDirectionSync) // 配置变更(比如修改折行规则、字号)时同步 editorA.onDidChangeConfiguration(biDirectionSync) editorB.onDidChangeConfiguration(biDirectionSync) // 初始化执行一次 biDirectionSync()
如果两个编辑器的行数不一致,可以按业务需求处理超出部分:比如给行数更少的编辑器末尾插入对应高度的空白填充,或者截断超出行数的同步逻辑即可。
对性能要求高的场景,可以监听onDidChangeViewZones事件做防抖处理,减少重复渲染次数。
内容的提问来源于stack exchange,提问作者qz-
相关产品推荐
相关产品推荐

