Vue 组件封装了 Ace Editor(一种代码编辑器)

77 min read
<template>
    <div class="ace">
        <el-button
            class="btn"
            style="margin-left: 380px;"
            icon="el-icon-search"
            @click="openSearchBox"
        >
            查找
        </el-button>
        <el-button
            class="btn"
            style="margin-left: 10px;"
            icon="el-icon-close"
            @click="closeEditor"
        >
            关闭
        </el-button>
        <div class="ace-editor">
            <div ref="ace" class="editor" />
        </div>
        <el-button
            type="primary"
            style="margin-left: 360px;"
            @click="setCode"
        >
            重置代码
        </el-button>
        <el-button
            type="success"
            style="margin-left: 20px;"
            @click="getCode"
        >
            保存提交
        </el-button>
    </div>
</template>

<script>
import ace from 'ace-builds'
import 'ace-builds/src-min-noconflict/theme-one_dark'
import 'ace-builds/src-min-noconflict/ext-searchbox'
import 'ace-builds/src-min-noconflict/mode-json5'
import 'ace-builds/src-min-noconflict/ext-language_tools'
import { mapState } from 'vuex'

export default {
    name: 'AceEditor',
    data() {
        return {
            editor: null,
            obj: null,
        }
    },
    computed: mapState([
        'canvasStyleData',
        'curComponent',
    ]),
    watch: {
        curComponent() {
            this.setCode()
        },
        canvasStyleData() {
            this.setCode()
        },
    },
    mounted() {
        ace.config.set('basePath', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.14/')
        this.editor = ace.edit(this.$refs.ace, {
            maxLines: 34,
            minLines: 34,
            fontSize: 14,
            theme: 'ace/theme/one_dark',
            mode: 'ace/mode/json5',
            tabSize: 4,
            readOnly: false,
            enableBasicAutocompletion: true,
            enableLiveAutocompletion: true,
            enableSnippets: true,
        })

        this.obj = this.curComponent || this.canvasStyleData
        this.editor.setValue(JSON.stringify(this.obj, null, 4))
    },
    methods: {
        setCode() {
            this.obj = this.curComponent || this.canvasStyleData
            this.editor.setValue(JSON.stringify(this.obj, null, 4))
        },

        getCode() {
            let str = this.editor.getValue()
            if (!this.curComponent) {
                this.$store.commit('aceSetCanvasData', JSON.parse(str))
            } else {
                this.$store.commit('aceSetcurComponent', JSON.parse(str))
            }
        },

        updateEditorTheme(theme) {
            this.editor.setTheme(theme)
        },

        openSearchBox() {
            this.editor.execCommand('find')
        },

        closeEditor() {
            this.$emit('closeEditor')
        },
    },
}
</script>

<style scoped>
.ace {
    position: absolute;
    height: calc(100% - 80px);
    width: 550px;
    top: 63px;
    background-color: #fff;
    border: 1px solid #ddd;
    z-index: 100;
}

.editor {
    margin: 10px 5px;
}
.btn {
    margin-top: 5px;
}
</style>

这个 Vue 组件是一个封装了 Ace Editor(一种代码编辑器)的接口,允许用户在网页上编辑和保存 JSON 格式的代码。

  • <template> 部分定义了组件的 HTML 结构。它有几个按钮,包括“查找”、“关闭”、“重置代码”和“保存提交”。它还有一个用于编辑器的 div,使用 ref 属性来引用它。

  • <script> 部分是组件的 JavaScript 代码。在 data 中,我们有两个数据项:editor 用于保存 Ace Editor 实例,obj 用于保存当前正在编辑的 JSON 对象。这个对象从 Vuex 的 state 中获取,取决于 curComponentcanvasStyleData

  • watch 中,我们监听了 curComponentcanvasStyleData 的变化。当任何一个发生变化时,我们都将使用新的数据更新编辑器的内容。

  • mounted 钩子中,我们初始化了 Ace Editor,设置了编辑器的各种选项,如行数、字体大小、主题、模式等,并使用初始的 JSON 数据填充编辑器。

  • methods 包含了一些方法,包括:

    • setCode:将当前的 JSON 对象(由 Vuex state 提供)格式化为字符串,并设置到编辑器中。
    • getCode:获取编辑器的内容,解析为 JSON 对象,并提交到 Vuex store。这个方法在用户点击“保存提交”按钮时调用。
    • updateEditorTheme:更新编辑器的主题。但是这个函数似乎并没有在任何地方被调用,可能是未完成的功能或者遗留代码。
    • openSearchBox:在编辑器中打开查找框。这个函数在用户点击“查找”按钮时调用。
    • closeEditor:关闭编辑器。实际上这个函数是触发一个名为 'closeEditor' 的自定义事件,组件的父组件可以监听这个事件并据此关闭编辑器。这个函数在用户点击“关闭”按钮时调用。
  • <style scoped> 部分定义了组件的 CSS 样式。scoped 属性确保这些样式只应用于当前组件,不会影响到其他的 Vue 组件。