使用 CodeMirror 只读模式的最佳实践

在开发中,我们经常会遇到需要在某些情况下展示代码,但不允许用户编辑的场景。一个常见的需求就是在查看历史提交时,只展示代码内容,不允许用户修改。这时,我们可以使用 CodeMirror 的只读模式来实现。

问题描述

在项目中,我需要实现一个代码查看的功能,要求代码在页面中只可读,不可修改。初步尝试了直接使用 CodeMirror 进行代码展示,但发现在用户点击代码区域时,依然可以进行编辑,这与我的需求不符。于是,我开始探索如何使用 CodeMirror 的只读模式。

以下是完整代码实现:

<template>
  <div class="code-mirror-box">
    <textarea ref="textareaCoder" v-model="code"></textarea>
  </div>
</template>

<script>
import _CodeMirror from 'codemirror'
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/monokai.css'
import 'codemirror/addon/selection/active-line.js'
import 'codemirror/addon/fold/foldgutter.css'
import 'codemirror/addon/fold/brace-fold.js'
import 'codemirror/addon/fold/comment-fold.js'
import 'codemirror/addon/fold/foldcode.js'
import 'codemirror/addon/fold/foldgutter.js'
import 'codemirror/addon/fold/indent-fold.js'
import 'codemirror/addon/fold/markdown-fold.js'
import 'codemirror/addon/fold/xml-fold.js'

const CodeMirror = window.CodeMirror || _CodeMirror

export default {
  name: 'code-mirror-box',
  props: ['conHeight', 'codeValue','editable'],
  data() {
    return {
      code: '',
      coder: null,
      options: {
        mode: 'javascript',
        tabSize: 2,
        theme: 'ambiance',
        lineNumbers: true,
        line: true,
        styleActiveLine: false,
        foldGutter: true,
        extraKeys: { Ctrl: 'autocomplete' },
        readOnly: '',
        lineWrapping: true,
        gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
      },
    }
  },
  created() {
    this.code = this.codeValue
    this.options.readOnly = this.editable
  },
  mounted() {
    this._initialize()
  },
  methods: {
    _initialize() {
      this.coder = CodeMirror.fromTextArea(
        this.$refs.textareaCoder,
        this.options
      )
      this.coder.on('change', (coder) => {
        this.code = coder.getValue()
      })
    },
    setValue(val) {
      this.coder.setValue(val)
    },
    refresh() {
      let timer = setTimeout(() => {
        clearTimeout(timer)
        this.$nextTick(() => {
          this.coder.refresh()
        })
      }, 100)
    },
  },
  watch: {
    code: {
      handler(val) {
        this.$emit('getCode', val)
      },
    },
  },
}
</script>

<style lang="less" scoped>
.code-mirror-box {
  font-size: 14px;
}
.CodeMirror {
  height: 100% !important;
}
.CodeMirror-scroll {
  height: 100%;
}
</style>

解决思路

在使用 CodeMirror 的过程中,只读模式是一个非常重要的功能。在 CodeMirror 的官方文档中,我们可以找到相关的 API 说明。通过使用 readOnly 属性,可以轻松实现代码编辑器的只读模式。

根据文档说明,readOnly 属性有两个主要选项:

  • true:禁用编辑,但允许聚焦(即用户可以点击并高亮代码)。
  • "nocursor":禁用编辑,并且不允许聚焦(即用户无法在代码编辑器中点击或高亮任何内容)。

通过设置 readOnly: "nocursor",我们可以确保用户不仅不能编辑代码,甚至无法点击编辑器内部的代码区域,从而完全实现代码只读的需求。

实现过程

  1. 设置 readOnly 属性:

    我们需要在 CodeMirror 的 options 中添加 readOnly 属性,并在 created() 钩子函数中根据实际需求赋值。

    created() {
      this.code = this.codeValue;
      this.options.readOnly = this.editable;  // 这里的editable可以是'true'或者是'nocursor'
    }
    
  2. 在组件调用中传递 editable 属性:

    在父组件中,我们可以通过传递 editable 属性来控制是否启用只读模式。例如,下面代码展示了如何在父组件中传递 nocursor 使得子组件只读不可编辑:

    <template>
      <div class="make-submit">
        <p>代码:</p>
        <code-mirror-box
          ref="codeMirror"
          :codeValue="lastSubmitData.code"
          :editable="'nocursor'"  // 设置为不可编辑且不可聚焦
        ></code-mirror-box>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          lastSubmitData: {
            code: 'console.log("Hello World!");'
          }
        }
      },
    }
    </script>
    
  3. 验证与调整:

    设置完成后,可以通过开发工具或直接在浏览器中进行验证。尝试点击代码编辑区域,确保代码无法编辑并且没有光标出现。如果出现异常,需检查 editable 属性的传递与 readOnly 配置是否正确。

进阶思考

在前端开发中,特别是在使用 Vue 等框架时,ref 是一个非常强大的工具。在这里,通过 ref 我们不仅能够获取到 DOM 元素,还可以直接操作这些元素的实例,这使得我们在实际开发中有了更多的可能性。

同时,在实际项目中,不仅仅是简单的展示代码或使其只读,还可能需要进一步的功能,如:

  • 代码高亮:根据不同的语言进行语法高亮。
  • 自动折叠:对于长代码块,自动进行折叠处理。
  • 自定义快捷键:在只读模式下,用户依然可以通过自定义快捷键进行一些特殊操作,如复制、查找等。

这些都是在实际项目中可以考虑并实现的扩展功能。

总结

通过这次的实践,我深刻体会到了在开发中深入理解工具的每一个细节是多么的重要。CodeMirror 作为一个强大的代码编辑器,通过简单的配置,就可以实现多种需求。在使用它的过程中,我们需要仔细阅读官方文档,了解每一个配置项的作用,并根据实际需求灵活应用。

希望这篇文章能帮助你更好地理解和使用 CodeMirror,尤其是在 Vue 项目中的应用。

Logo

前往低代码交流专区

更多推荐