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

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

作者: 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