返回 导航

Vue.js

hangge.com

Vue.js - 集成CodeMirror实现代码编辑器功能(语言高亮、关键字高亮)

作者:hangge | 2025-12-18 08:50
    CodeMirror 是一个功能强大的代码编辑器内核(基于浏览器),常用于在线代码编辑、配置编辑器、富文本差异显示等场景。它支持丰富的语言高亮、主题、快捷键、扩展(addon)等。下面我将演示在 Vue 项目中如何集成 CodeMirror,包括把 CodeMirror 封装为一个组件,支持 v-model(双向绑定)、外部配置传入和事件回调,方便复用。

1,安装依赖

进入项目的根目录,执行如下命令安装 CodeMirror v5 版本:
npm install codemirror@5

2,封装一个自定义组件

为方便使用,我们创建一个 CodeMirrorEditor.vue 组件,支持 v-model、传入 options、外部更新同步和卸载清理。
<template>
    <div class="cm-wrapper">
        <!-- 使用 textarea 以便后续销毁时能调用 toTextArea() 安全销毁 -->
        <textarea ref="textarea"></textarea>
    </div>
</template>

<script>
import CodeMirror from 'codemirror'
import 'codemirror/lib/codemirror.css'  // 基础样式
import 'codemirror/theme/dracula.css' // 可选主题

import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/mode/xml/xml.js'     // html 使用 xml 或 htmlmixed
import 'codemirror/mode/css/css.js'
import 'codemirror/addon/edit/closebrackets.js'   // 自动闭合括号
import 'codemirror/addon/comment/comment.js'      // 注释快捷键
import 'codemirror/addon/fold/foldcode.js'        // 折叠
import 'codemirror/addon/selection/active-line.js'// 当前行高亮

export default {
    name: 'CodeMirrorEditor',
    props: {
        value: { type: String, default: '' },  // 绑定的文本内容
        options: { type: Object, default: () => ({}) } //CodeMirror初始化配置(lineNumbers, mode等)
    },
    mounted() {
        // // 合并默认配置
        const defaultOptions = {
            value: this.value || '',
            lineNumbers: true,
            mode: 'javascript',
            theme: 'dracula',
            autoCloseBrackets: true
        }
        // 用 fromTextArea 创建编辑器,便于销毁
        this.editor = CodeMirror.fromTextArea(this.$refs.textarea,
            Object.assign({}, defaultOptions, this.options))
        // 初始化后主动设置一次内容
        if (this.value) {
            this.editor.setValue(this.value)
        }
        //  编辑器内容变化时向外发出input事件
        this.editor.on('change', () => {
            const val = this.editor.getValue()
            this.$emit('input', val)
        })
    },
    watch: {
        // 如果外部 modelValue 变更(非来自编辑器),同步到编辑器
        value(newVal) {
            if (!this.editor) return
            if (this.editor.getValue() !== newVal) {
                this.editor.setValue(newVal || '')
            }
        }
    },
    // 组件卸载,销毁编辑器并恢复 textarea
    beforeDestroy() {
        if (this.editor && typeof this.editor.toTextArea === 'function') {
            this.editor.toTextArea()
            this.editor = null
        }
    }
}
</script>

<style scoped>
.cm-wrapper .CodeMirror {
    height: 400px;
}
</style>

3,使用样例

(1)下面是用这个自定义组件,并传入初始内容:
<template>
    <CodeMirrorEditor v-model="code" :options="{ mode: 'javascript', lineNumbers: true }" />
</template>
<script>
import CodeMirrorEditor from './codemirror/CodeMirrorEditor.vue'
export default {
    components: { CodeMirrorEditor },
    data() {
        return {
            code: `const users = [
    { id: 1, name: 'Alice',s: 30 }
]

// 箭头函数
const getUserNames = () => users.map(u => u.name)

// async / await 示例
async function loadUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
        const user = users.find(u => u.id === id)
        user ? resolve(user) : reject(new Error('Not found'))
        }, 500)
    })
}`
        }
    }
}
</script>

(2)运行效果如下,可以看到代码已经具有语法高亮效果,并且我们可以自由编辑。

附:进阶技巧

1,只读模式

(1)如果希望只能展示不能编辑,可以将 CodeMirrorreadOnly 属性设置为 true,此时编辑器不可输入、可选中、可复制。但该模式下还是有鼠标光标。
<CodeMirrorEditor v-model="code" :options="{ 
    mode: 'javascript', 
    lineNumbers: true,
    readOnly: true }" 
/>

(2)如果希望只读模式下光标也不显示,那么可以将 readOnly 属性设置为 'nocursor'
<CodeMirrorEditor v-model="code" :options="{
    mode: 'javascript',
    lineNumbers: true,
    readOnly: 'nocursor'}" 
/>

2,设置主题样式

(1)前面的样例我们使用的是 dracula 这个暗色主题。CodeMirror 自带了很多官方主题,不需要额外 npm 安装,只要 import 对应的 .css 就能用。想要知道本地有哪些主题可以打开项目如下路径查看:
node_modules/codemirror/theme/

(2)下面是官方内置主题完整列表:
深色主题 浅色主题
3024-night
abbott
abcdef
ambiance
ayu-dark
base16-dark
bespin
blackboard
cobalt
colorforth
darcula
dracula
duotone-dark
elegant
erlang-dark
hopscotch
icecoder
isotope
lesser-dark
liquibyte
lucario
material
material-darker
material-ocean
material-palenight
monokai
night
nord
oceanic-next
panda-syntax
paraiso-dark
railscasts
rubyblue
seti
shadowfox
the-matrix
tomorrow-night-bright
tomorrow-night-eighties
ttcn
twilight
vibrant-ink
xq-dark
yonce
zenburn
3024-day
base16-light
default
eclipse
idea
mdn-like
neo
paraiso-light
ssms
yeti
xq-light

(3)下面样例我们改用 idea 浅色主题进行代码高亮显示,修改 CodeMirrorEditor.vue 组件。
<template>
    <div class="cm-wrapper">
        <!-- 使用 textarea 以便后续销毁时能调用 toTextArea() 安全销毁 -->
        <textarea ref="textarea"></textarea>
    </div>
</template>

<script>
import CodeMirror from 'codemirror'
import 'codemirror/lib/codemirror.css'  // 基础样式
import 'codemirror/theme/idea.css' // 可选主题

import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/mode/xml/xml.js'     // html 使用 xml 或 htmlmixed
import 'codemirror/mode/css/css.js'
import 'codemirror/addon/edit/closebrackets.js'   // 自动闭合括号
import 'codemirror/addon/comment/comment.js'      // 注释快捷键
import 'codemirror/addon/fold/foldcode.js'        // 折叠
import 'codemirror/addon/selection/active-line.js'// 当前行高亮

export default {
    name: 'CodeMirrorEditor',
    props: {
        value: { type: String, default: '' },  // 绑定的文本内容
        options: { type: Object, default: () => ({}) } //CodeMirror初始化配置(lineNumbers, mode等)
    },
    mounted() {
        // // 合并默认配置
        const defaultOptions = {
            value: this.value || '',
            lineNumbers: true,
            mode: 'javascript',
            theme: 'idea',
            autoCloseBrackets: true
        }
        // 用 fromTextArea 创建编辑器,便于销毁
        this.editor = CodeMirror.fromTextArea(this.$refs.textarea,
            Object.assign({}, defaultOptions, this.options))
        // 初始化后主动设置一次内容
        if (this.value) {
            this.editor.setValue(this.value)
        }
        //  编辑器内容变化时向外发出input事件
        this.editor.on('change', () => {
            const val = this.editor.getValue()
            this.$emit('input', val)
        })
    },
    watch: {
        // 如果外部 modelValue 变更(非来自编辑器),同步到编辑器
        value(newVal) {
            if (!this.editor) return
            if (this.editor.getValue() !== newVal) {
                this.editor.setValue(newVal || '')
            }
        }
    },
    // 组件卸载,销毁编辑器并恢复 textarea
    beforeDestroy() {
        if (this.editor && typeof this.editor.toTextArea === 'function') {
            this.editor.toTextArea()
            this.editor = null
        }
    }
}
</script>

<style scoped>
.cm-wrapper .CodeMirror {
    height: 400px;
}
</style>

(4)最后显示效果如下:

3,设置语言 mode

(1)CodeMirror v5 的语言高亮是通过 mode 实现的。其自带的 mode 非常多,覆盖了几乎所有常见编程/标记/配置语言。要查看完整 mode 列表,可以打开项目的如下路径。这下面每一个文件夹都是一个可用 mode
node_modules/codemirror/mode/

(2)下面表格整理了市面上常用语言以及对应的 mode
语言 Mode Import 路径
JavaScript javascript codemirror/mode/javascript/javascript.js
TypeScript javascript codemirror/mode/javascript/javascript.js
JSON javascript codemirror/mode/javascript/javascript.js
HTML htmlmixed codemirror/mode/htmlmixed/htmlmixed.js
CSS css codemirror/mode/css/css.js
Vue htmlmixed HTML(依赖 xml / js / css
Markdown markdown codemirror/mode/markdown/markdown.js
YAML yaml codemirror/mode/yaml/yaml.js
XML xml codemirror/mode/xml/xml.js
Java clike codemirror/mode/clike/clike.js
C / C++ clike codemirror/mode/clike/clike.js
C# clike codemirror/mode/clike/clike.js
Go go codemirror/mode/go/go.js
Python python codemirror/mode/python/python.js
PHP php codemirror/mode/php/php.js
Ruby ruby codemirror/mode/ruby/ruby.js
Shell / Bash shell codemirror/mode/shell/shell.js
PowerShell powershell codemirror/mode/powershell/powershell.js
SQL sql codemirror/mode/sql/sql.js
Redis redis codemirror/mode/redis/redis.js
Nginx nginx codemirror/mode/nginx/nginx.js
Dockerfile dockerfile codemirror/mode/dockerfile/dockerfile.js
TOML toml codemirror/mode/toml/toml.js
INI / Conf properties codemirror/mode/properties/properties.js
Less less codemirror/mode/css/css.js
SCSS / Sass sass / scss codemirror/mode/sass/sass.js
Stylus stylus codemirror/mode/stylus/stylus.js
JSX jsx codemirror/mode/jsx/jsx.js
Handlebars handlebars codemirror/mode/handlebars/handlebars.js
Pug pug codemirror/mode/pug/pug.js
CSV spreadsheet codemirror/mode/spreadsheet/spreadsheet.js
Diff diff codemirror/mode/diff/diff.js
LaTeX stex codemirror/mode/stex/stex.js

(3)假设我们需要实现 sql 语言高亮,首先在 CodeMirrorEditor.vue 组件中引入对应 modejs
import 'codemirror/mode/sql/sql.js'

(4)然后使用该组件时将 mode 设置为'sql'
<CodeMirrorEditor v-model="code" :options="{
    mode: 'sql',
    lineNumbers: true
}" />

(5)最后效果如下图所示:
评论

全部评论(0)

回到顶部