目录
前言
最近公司要求用Monaco Editor实现类似vscode断点功能,具体成果如下
我的需求:
- 鼠标点击行号增加/取消断点
- 支持自定义断点样式
实现一:鼠标点击创建断点
首先在创建editor实例时设置glyphMargin:true,这是为了启用图形边距的渲染,在vscode种是默认为true,但在monaco editor中默认为false。
editor = monaco.editor.create(dom, {
..., // 你的其他配置
glyphMargin: true,
})
接下来需要监听鼠标事件onMouseDown,这里我是用的react写法
const onToggleBreakPoint = useCallback(() => {
editor.onMouseDown((e: { target }) => {
const { type, position } = e.target;
if (![2].includes(type)) return;
... // 鼠标点击回调操作
});
}, []);
在回调函数中获取到event事件,其中type===2时,表示点击区域为创建断点区域(有时候需要点击面积扩大时可以加上3,4类型)
现在通过回调event事件得到position,创建断点对象
// 创建断点范围
const range = {
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: 1,
};
// 创建断点对象
const breakPointDec = {
range,
options: {
isWholeLine: true,
className: "contentClass",
marginClassName: "myGlyphMarginClass", // 断点css样式类
stickiness:
monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
},
};
// 设置断点
editor.getModel().deltaDecorations([], [breakPointDec]);
这里注意stickiness,亲测必须设置该属性为monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,才能让断点成功跟随行号,stickiness具体属性如下
实现二:自定义断点样式
.myGlyphMarginClass {
top: 4px !important;
left: 10px !important;
width: 10px !important;
height: 10px !important;
background: red !important;
border-radius: 50%;
}
实现三:添加断点创建/取消逻辑
大概思路:
通过editor.getModel().getLineDecorations(position.lineNumber)获取行装饰器,返回的是array,通过遍历行装饰器查找className="myGlyphMarginClass"的装饰id且存储该id,后续判断有用。
判断decorationIds长度,若为0则表示需要创建断点,反之则为取消断点。
const editor = monaco.editor.create(dom, {
..., // 你的其他配置
glyphMargin: true,
});
const decorationIds = [];
editor.onMouseDown((e: { target }) => {
const { type, position } = e.target;
if (![2, 3, 4].includes(type)) return;
const lineDecoration = editor.getModel().getLineDecorations(position.lineNumber);
let flagId = "";
lineDecoration.forEach((decoration) => {
if (decoration.options.marginClassName === "myGlyphMarginClass") {
decorationIds.push(decoration.id);
flagId = decoration.id;
}
});
if (decorationIds.length === 0) {
const range = {
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: 1,
};
const breakPointDec = {
range,
options: {
isWholeLine: true,
className: "contentClass",
marginClassName: "myGlyphMarginClass",
stickiness:
monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
},
};
editor.getModel().deltaDecorations([], [breakPointDec]);
} else {
const index = decorationIds.findIndex((id) => id === flagId);
editor.getModel().deltaDecorations(decorationIds, []);
decorationIds.splice(index, 1);
}
});
以上方案如有错误之处,还请各位指出,后续会进行改正