CodeMirror 笔记

这篇文章用来记录使用 CodeMirror 时的一些心得。

Demo

CodeMirror 官方提供很多 Demo 供我们参考,通过阅读这些 Demo 的源码可以解决很多使用时遇到的问题。

https://codemirror.net/demo/

Vue

配合 Vue 使用的时候,我们一般会在 mounted 里初始化 CodeMirror 实例,然后在别的什么地方加载数据,然后通过 cm.setValue(code) 的方式写入代码。

这么做大体上 OK,不过在用户不断 Ctrl + Z 的时候,会清空代码。因为 CodeMirror 初始化的时候里面没有代码,我们第一次 cm.setValue(code) 就会把这个动作放在 history 的第一位,所以后退的时候,清空所有代码也是合理的。

要解决这个问题,一方面,我们可以加载完数据再执行初始化,不过这样页面会跳动,体验不好;或者,第一次填充完代码,清空历史,也可以。

methods: {
  async fetch() {
    const code = await fetchCode();
    this.editor.setValue(data.content);
    this.editor.clearHistory();
  }
},
beforeMount() {
  this.fetch();
},
mounted() {
  this.editor = new CodeMirror.fromTextArea(this.$refs.editor, {...});
  this.editor.on('change', cm => {
    cm.save();
    this.code = cm.getValue();
  });
},

keyMapextraKeys

作为一个 IDE,CodeMirror 自然支持各种键位配置,keyMap 就是用来定义这些键位配置的。它可以是一个字符串或者数组,字符串对应一种配置,数组对应多种配置,CodeMirror 会自动降级适配。

除此之外,用户还可以通过 extraKeys 定义一些自己偏爱的个性化配置,比如我厂常用的:

  1. Tab 插入空格
  2. Shift+Tab 减少缩进
  3. 删除整个缩进

实现起来是这样的:

CodeMirror.fromTextArea(this.$refs.editor, {
  // ...其它配置
  extraKeys: {
    Tab(cm) {
      if (cm.somethingSelected()) {
        cm.indentSelection('add');
        return;
      }
      cm.replaceSelection('    ', 'end', '+input');
    },
    'Shift-Tab'(cm) {
      cm.indentSelection('subtract');
    },
    Backspace(cm) {
      // 取当前行光标前面的字符,如果都是空格,就减少有一个缩进
      let {line, ch} = cm.getCursor();
      line = cm.getLine(line).substr(0, ch);
      if (line.length > 0 && line.trim() === '') {
        cm.indentSelection('subtract');
        return;
      }
      // 表示使用 CodeMirror 默认行为
      return CodeMirror.Pass;
    },
  },
});

启用搜索,侦听全局 Ctrl + F

CodeMirror 自带搜索功能,不过默认没有启动,需要引入一些组件。

import 'codemirror/addon/dialog/dialog';
import 'codemirror/addon/scroll/annotatescrollbar';
import 'codemirror/addon/search/matchesonscrollbar';
import 'codemirror/addon/search/jump-to-line';
import 'codemirror/addon/search/search';
import 'codemirror/addon/search/searchcursor';

接下来,在 CodeMirror 里 Ctrl+F(Mac 下是 Cmd+F)就会打开搜索面板。不过很多时候我们的编辑器页面里就只有一个 CodeMirror,这个时候我们就要侦听全局的 Ctrl + F,并且启动搜索面板。

我们只需要让 CodeMirror 执行 find 命令即可:

methods: {
  onKeyDown(event) {
    const isMac = navigator.platform.startsWith('Mac');
    const {key, code, keyCode, ctrlKey, metaKey} = event;
    const isCmd = isMac && metaKey || !isMac && ctrlKey;
    if (!isCmd) {
      return;
    }
    const isF = key === 'f' || code === 'KeyF' || keyCode === 70;
    if (isF && this.editor) {
      this.editor.execCommand('find');
      event.preventDefault();
    }
  },
},
beforeMount() {
  this.onKeyDown = this.onKeyDown.bind(this);
  document.addEventListener('keydown', this.onKeyDown);
}

常见用法

const {line, ch} = cm.getCursor();
cm.replaceRange('# ', {line, ch});
const {line} = cm.getCursor();
const tokens = cm.getLineTokens(line);
if (tokens.length === 1 && tokens[0].type === 'comment') {
  // do something
}

如果您觉得文章内容对您有用,不妨支持我创作更多有价值的分享:


已发布

分类

来自

标签:

评论

欢迎吐槽,共同进步

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据