美文网首页
编辑器实现自定义高亮关键字、提示输入操作

编辑器实现自定义高亮关键字、提示输入操作

作者: Xbbing | 来源:发表于2024-03-11 11:22 被阅读0次

效果展示

image.png

前置

npm i codemirror@5.65.5 //锁定版本

组件

<!--
 * @Descripttion: 代码编辑器
 * @version: 1.0
 * @Author: bing
 * @Date: 2024年3月1日
 * @LastEditors: 
 * @LastEditTime: 
-->

<template>
    <div class="bing-code-editor" :style="{'height':_height}">
        <textarea ref="textarea" v-model="contentValue"></textarea>
    </div>
</template>

<script>
    import { markRaw } from "vue"

    //框架
    import CodeMirror from 'codemirror'
    import 'codemirror/lib/codemirror.css'

    //主题
    import 'codemirror/theme/idea.css'
    import 'codemirror/theme/darcula.css'

    //功能
    import 'codemirror/addon/selection/active-line'

    //语言
    import 'codemirror/mode/javascript/javascript'
    import 'codemirror/mode/sql/sql'


    import 'codemirror/addon/hint/show-hint.js'
    import 'codemirror/addon/hint/show-hint.css'

    import 'codemirror/addon/hint/sql-hint.js'

    export default {
        props: {
            modelValue: {
                type: String,
                default: ""
            },
            mode: {
                type: String,
                default: "javascript"
            },
            height: {
                type: [String,Number],
                default: 300,
            },
            options: {
                type: Object,
                default: () => {}
            },
            theme: {
                type: String,
                default: "idea"
            },
            readOnly: {
                type: Boolean,
                default: false
            },
        },
        data() {
            return {
                contentValue: this.formatStrInJson(this.modelValue),
                coder: null,
                keywords: [
                    ['吃了', "keyword"],
                    ['兵兵', "property"],
                    ['徐', "number"],
                    ['牛肉', "comment"]
                ],
                opt: {
                    theme: this.theme,  //主题
                    styleActiveLine: true,  //高亮当前行
                    lineNumbers: true,  //行号
                    lineWrapping: true, //自动换行
                    tabSize: 4, //Tab缩进
                    indentUnit: 4,  //缩进单位
                    indentWithTabs : true,  //自动缩进
                    mode : this.mode,   //语言
                    readOnly: this.readOnly,    //只读
                    lint: true, // 格式化
                    foldGutter: true, // 启用折叠效果
                    hintOptions: { // 代码提示
                        completeSingle: false, // 当匹配只有一项的时候是否自动补全
                        hint: this.bingShowHint // 自定义提示
                    },
                    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'], // 配置折叠参数
                    ...this.options
                },
                isBlank: false, // 是否为空格
                start: null // 光标开始位置
            }
        },
        computed: {
            _height() {
                return Number(this.height)?Number(this.height)+'px':this.height
            },
        },
        watch: {
            modelValue(val) {
                this.contentValue = val
                if (val !== this.coder.getValue()) {
                    const format = this.formatStrInJson(val)
                    this.coder.setValue(format)
                }
            }
        },
        mounted() {
            this.init()
            //获取挂载的所有modes
            //console.log(CodeMirror.modes)
        },
        methods: {
            init(){
                const _this = this
                // 颜色变换[高亮自定义关键词]
                CodeMirror.defineMode('javascript', function() {
                    return {
                        token: (stream, state) => {
                            const cmCustomCheckStreamFn = (streamWrapper) => {
                                for (let i = 0; i < _this.keywords.length; i++) {
                                    if (streamWrapper.match(_this.keywords[i][0])) { return _this.keywords[i][1] }
                                }
                                return ''
                            }
                            const ret = cmCustomCheckStreamFn(stream)
                            if(ret.length > 0) return ret
                            stream.next()
                            return null
                        }
                    }
                })

                this.coder = markRaw(CodeMirror.fromTextArea(this.$refs.textarea, this.opt))
                this.coder.on('change', (coder, data) => {
                    // console.log(this.inputFilter(data.text))
                    this.contentValue = coder.getValue()
                    this.$emit('update:modelValue', this.contentValue)
                })
                // 输入或者粘贴时触发
                this.coder.on('inputRead', (coder) => {
                    const cursor = coder.getDoc().getCursor()
                    const token = coder.getTokenAt(cursor)
                    console.log(token.string)
                    if((token.string).trim() == '') {
                        this.start = token.start + 1
                    }
                    if(this.start === null) {
                        this.start = token.start
                    }
                    const currentData = this.inputFilter(token.string)
                    if(currentData) {
                        coder.showHint()
                    }
                })
            },
            // 输入过滤
            inputFilter(data) {
                var reg = /^[\u4e00-\u9fa5]+$/;
                if(!reg.test(data)) {
                    return false
                }else {
                    return data
                }
            },
            // 自定义弹窗内容
            bingShowHint(cmInstance) {
                let cursor = cmInstance.getCursor()
                let token = cmInstance.getTokenAt(cursor)
                return {
                    list: [ 
                        {
                            text: '吃了',
                            displayText: '吃了',
                            displayInfo: '吃了',
                        },
                        {
                            text: '徐',
                            displayText: '徐',
                            displayInfo: '徐',
                        },
                        {
                            text: '兵兵',
                            displayText: '兵兵',
                            displayInfo: '兵兵',
                        }
                    ],
                    from: {
                        // ch: token.start, line: cursor.line
                        ch: this.start, line: cursor.line
                    },
                    to: {
                        ch: token.end, line: cursor.line
                    }
                }
            },
            formatStrInJson(strValue) {
                // return JSON.stringify(JSON.parse(strValue), null, 4)
                return strValue
            }
        }
    }
</script>

<style scoped>
    .bing-code-editor {font-size: 14px;border: 1px solid #ddd;line-height: 150%;}
    .bing-code-editor:deep(.CodeMirror)  {height: 100%;}
</style>

组件使用


<script setup>
import scCodeEditor from '@/components/bingEditor/index.vue'
import { ref } from 'vue'

const demoValue = ref('')
</script>

<template>
  <div class="editor">
    <sc-code-editor v-model="demoValue" mode="javascript" height="100vh" theme="darcula"></sc-code-editor>
  </div>
</template>

<style scoped>
.editor {
  width: 100%;
  height: 100%;
}
</style>

相关文章

网友评论

      本文标题:编辑器实现自定义高亮关键字、提示输入操作

      本文链接:https://www.haomeiwen.com/subject/vwsmzdtx.html