CodeMirror 中固定滚动位置
CodeMirror 是最流行的代码编辑器之一,包括写作软件 WonderPen 在内的很多工具都使用它开发。
与印象笔记等笔记软件不同,WonderPen 的定位是一款写作软件。写作软件与笔记软件之间有很多区别,最大的不同就是前者更专注于提升写作时的体验,而后者则更专注于数据的存储与连接。写作软件中有一个常见的特性,「打字机模式」。
打字机模式
在 Word 等大多数编辑软件中,如果你输入了很多内容,超过一屏之后,光标通常会位于屏幕最下方,这时除非你滚动一下文档,否则光标会一直处于屏幕最下的位置,你的视线也只能一直盯在这个位置,这对需要长时间输入的用户来说并不友好。所谓打字机模式,其实就是像传统的打字机一样,在用户输入时将光标在屏幕上的 y 坐标固定(比如固定在屏幕中间),这样便能保持用户视线高度固定。在技术上来说,就是固定文档的滚动位置。
在 CodeMirror 中,实现这样的功能很简单,下面是一个例子。
首先,我们生成一个 CodeMirror 编辑器实例
const cm = CodeMirror(document.body, {
lineNumbers: true
});
cm.setSize("100%", "100%");
我们并不需要让滚动条一直固定,因为有时候用户需要手动滚动文档,查看上方或下方的内容,因此我们只需要监听它的 change
事件,并在每次事件触发时更新滚动位置。
cm.on("changes", (cm, changes) => updateByTypewriterMode(cm, changes));
这儿的 updateByTypewriterMode()
函数是我们的一个自定义函数,CodeMirror 会传入两个参数进去,分别是当前 CodeMirror 编辑器的实例以及本次 change
事件对应的修改内容。
updateByTypewriterMode()
函数的内容如下:
function updateByTypewriterMode(cm, changes) {
if (cm.getSelection().length !== 0) {
return;
}
const scroll_origins = ["+input", "+delete", "*compose", "paste"];
for (let i = 0, len = changes.length; i < len; i++) {
let each = changes[i];
let origin = each.origin;
if (scroll_origins.includes(origin)) {
cm.execCommand("wpScrollSelectionToCenter");
return;
}
}
}
在发生指定类型的修改时,执行 CodeMirror 的命令 wpScrollSelectionToCenter
。这个命令是一个自定义命令,定义如下:
CodeMirror.commands.wpScrollSelectionToCenter = function(cm) {
if (cm.getOption("disableInput")) {
return CodeMirror.Pass;
}
// 获取当前光标所在位置
let top = cm.cursorCoords(true, "local").top;
// 获取当前编辑器高度
let editor_height = cm.getWrapperElement().offsetHeight;
// 获取当前行高
let lh = cm.defaultTextHeight();
let scroll_y = Math.round(top - editor_height / 2 + lh / 2);
cm.scrollTo(null, scroll_y);
};
同时,我们可以再用 CSS 给编辑器下方添加一定高度的空白,保证需要的时候滚动条有足够的空间。
.CodeMirror-lines {
padding-bottom: 50%;
}
这样,打字机模式就基本完成了,用户输入内容时,如果文档长度已经超过容器高度的一半,则光标所在行会自动滚动到屏幕中间。
示例
你可以点击这儿,查看在线的完整示例。此例中,你可以在 CodeMirror 编辑器中随意输入内容,可以看到光标始终会保持在容器的上 1/2 位置。
评论: