最近在琢磨前端,因项目中需要在页面上编辑代码,所以需要写一个代码编辑器供用户使用。找了几个编辑器相关的组件,对比了下感觉还是vue2-ace-editor用着舒服,写了demo供大家参考。
由于我的项目使用的是vue2,二开鹅厂的bk-ci(蓝盾),因此基础组件使用的是bk组件。大家可以把选择框、按钮这些替换成自己使用的组件(如element-ui等)
组件已经封装好可以直接到手使用,支持更换主题、切换语言、缩进、搜索和替换(编辑器内Ctrl+F)、复制,json美化等...
效果图:
首先,到项目中安装插件:
npm install --save-dev vue2-ace-editor
安装成功后,引用组件,可在main.js中全局引用:
import Editor from 'vue2-ace-editor'
Vue.component('editor', Editor)
或直接在代码中局部引用(如我这里直接代码中引用):
<template>
<div>
<bk-card title="代码编辑器">
<div style="display: flex; width: 100%; margin-right: 20px; margin-bottom: 10px;">
<bk-select
:disabled="false"
placeholder="请选择主题"
search-placeholder="搜索主题"
v-model="valueTheme"
style="width: 150px; margin-right: 20px;"
@change="selectTheme"
searchable>
<bk-option v-for="option in listTheme"
:key="option"
:id="option"
:name="option">
</bk-option>
</bk-select>
<bk-select
:disabled="false"
placeholder="请选择语言"
search-placeholder="搜索语言"
v-model="valueCodeLang"
style="width: 150px; margin-right: 20px;"
@change="selectLang"
:font-size="large"
searchable>
<bk-option v-for="option in listCodeLang"
:key="option"
:id="option"
:name="option">
</bk-option>
</bk-select>
<bk-button theme="primary" icon="script-file" class="mr10" @click="copyCode()"> 复制代码</bk-button>
<bk-button v-if="valueCodeLang === 'json'" theme="primary" icon="eye" class="mr10" @click="formatCode()"> 美化代码</bk-button>
</div>
<editor
ref="aceEditor"
v-model="content"
@init="editorInit"
width="100%"
height="400px"
:lang="lang"
:theme="theme"
:options="{
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
tabSize: 6, fontSize: 14,
readOnly: readOnly,//设置是否只读
showPrintMargin: false //去除编辑器里的竖线
}"
></editor>
</bk-card>
</div>
</template>
<script>
export default {
components: {
editor: require('vue2-ace-editor')
},
props: {
// 是否只读
readOnly: {
type: Boolean,
default: false
},
// 要展示的代码
codeData: {
type: String,
default: ''
},
// 默认的主题
valueTheme: {
type: String,
default: 'dracula'
},
// 默认的语言
valueCodeLang: {
type: String,
default: 'json'
}
},
data () {
return {
listTheme: [
'dracula',
'chrome',
'chaos',
'clouds',
'clouds_midnight',
'xcode',
'monokai',
'ambiance',
'dreamweaver',
'eclipse',
'github',
'idle_fingers'
],
listCodeLang: [
'json',
'yaml',
'xml',
'java',
'text',
'javascript',
'scheme',
'lua',
'mysql',
'perl',
'powershell',
'python',
'ruby',
'sql',
'hjson',
'ini'
],
content: '',
theme: '',
lang: ''
}
},
mounted () {
// 初始化编辑器
this.editorInit()
// 初始化主题、语言
this.theme = this.valueTheme
this.lang = this.valueCodeLang
// 若传输代码,则展示代码
if (this.codeData) {
console.log(this.codeData)
this.$refs.aceEditor.editor.setValue(this.codeData)
}
},
methods: {
selectTheme (newValue, oldValue) {
if (newValue) {
this.theme = newValue
}
},
selectLang (newValue, oldValue) {
if (newValue) {
this.lang = newValue
}
},
editorInit () { // 初始化
require('brace/ext/language_tools')
require('brace/ext/beautify')
require('brace/ext/error_marker')
require('brace/ext/searchbox')
require('brace/ext/split')
// 循坏加载语言,通过点击按钮切换
for (let s = 0; s < this.listCodeLang.length; s++) {
require('brace/snippets/' + this.listCodeLang[s])
}
for (let j = 0; j < this.listCodeLang.length; j++) {
require('brace/mode/' + this.listCodeLang[j])
}
// 循坏加载主题,通过点击按钮切换
for (let i = 0; i < this.listTheme.length; i++) {
require('brace/theme/' + this.listTheme[i])
}
},
copyCode () {
const code = this.$refs.aceEditor.editor.getValue()
// 复制到剪切板
if (navigator.clipboard) {
navigator.clipboard.writeText(code)
// 复制成功 给提示 此处省略
} else {
// 复制失败 给提示 此处省略
alert('您的浏览器不支持自动复制,请手动复制')
}
},
formatCode () {
const string = JSON.stringify(JSON.parse(this.$refs.aceEditor.editor.getValue()), null, 2)
this.$refs.aceEditor.editor.setValue(string)
}
// getValue () { // 获取编辑器中的值
// console.log('编辑器中第一个换行符的位置:' + this.$refs.aceEditor.editor.getValue().indexOf('\n'))
// }
}
}
</script>
<style>
</style>
开发中遇到关于 'Unexpected token '<'' 的报错的话,要先加载 “brace/snippets/” 再加载 “brace/mode/” 。顺序不对就会报错!