CodeMirror(代码编辑器)vue使用及placeholder实现

CodeMirror(代码编辑器)vue使用及placeholder实现

组件封装

<template>
  <div class="container" :style="{ width: mWidth + 'px', height: mHeight + 'px' }">
    <textarea ref="textarea" :placeholder="placeholder"></textarea>
  </div>
</template>

<script>
// 引入核心配置包
import _CodeMirror from 'codemirror/lib/codemirror';
import 'codemirror/lib/codemirror.css';
// 引入主题对应的样式包
import 'codemirror/theme/monokai.css';
// 引入主题代码编辑模块的包
import 'codemirror/mode/javascript/javascript';
// import 'codemirror/mode/vue/vue';
// import 'codemirror/mode/xml/xml';
// 引入自动补全的包
// import 'codemirror/addon/hint/javascript-hint';
// import 'codemirror/addon/hint/html-hint';
// import 'codemirror/addon/hint/xml-hint';
// import 'codemirror/addon/hint/css-hint';
import 'codemirror/addon/selection/active-line';
import 'codemirror/addon/edit/closebrackets.js';
// 滚动条
import 'codemirror/addon/scroll/simplescrollbars.css'
import 'codemirror/addon/scroll/simplescrollbars.js'
// 自动提示
import 'codemirror/addon/hint/show-hint';
// 自动刷新解决刚开始数据挂载错误问题
import './autoRefresh';

const CodeMirror = window.CodeMirror || _CodeMirror;
const compare = (str1, str2) => {
  if (!str1.trim() || !str2.trim()) return false;
  // 去除空格
  const strToken = str => {
    const arr = [];
    str = str.trim();
    let left = 0;
    let right = 0;
    while (right < str.length) {
      if (str[right] === ' ' && str[right + 1] !== ' ') {
        arr.push(str.slice(left, right).trim());
        left = right;
      }
      right++;
    }
    return arr;
  };

  const arr1 = strToken(str1);
  const arr2 = strToken(str2);
  if (arr1.length !== arr2.length) return false;
  let index = 0;
  const len = arr1.length;
  while (index < len) {
    if (arr1[index] !== arr2[index]) return false;
    index++;
  }
  return true;
};
export default {
  name: 'SkyCodeMirror',
  props: {
    // 外部传入的内容,用于实现双向绑定
    codeStr: {
      type: String,
      default: null
    },
    // 外部传入的语法类型
    language: {
      type: String,
      default: 'javascript'
    },
    isReadOnly: {
      type: Boolean,
      default: false
    },
    mWidth: {
      type: Number,
      default: 195
    },
    mHeight: {
      type: Number,
      default: 180
    },
    placeholder: {
      type: String,
      default: ''
    }
  },
  emits: ['input'],
  data() {},
  mounted() {
    this.init();
  },
  methods: {
    init() {
      const myTextarea = this.$refs.textarea;
      // 初始化codeMirror
      const codeMirror = CodeMirror.fromTextArea(myTextarea, {
        mode: this.language, // 编辑器语言
        theme: 'monokai', // 主题
        autoRefresh: true, // 自动刷新
        line: true,
        value: '',
        tabSize: 2,
        lineWrapping: true, // 自动换行
        smartIndent: true,
        styleActiveLine: true,
        autoCloseBrackets: true,
        readOnly: this.isReadOnly,
        scrollbarStyle: 'simple',
        extraKeys: { 'Ctrl': 'autocomplete' }
      });
      
      codeMirror.setSize(this.mWidth,this.mHeight)
      // 设置值
      this.initValue(codeMirror);
      codeMirror.on('focus', () => {
        // // 刚开始聚焦解决聚焦问题
        // codeMirror.setCursor({
        //   line: 1,
        //   ch: 5
        // });
        const code = codeMirror.getValue();
        // 聚焦的时候清除placeholder
        if (compare(code, this.placeholder)) {
          codeMirror.setValue('');
        } else {
          codeMirror.setValue(code);
        }
      });
      codeMirror.on('blur', () => {
        const code = codeMirror.getValue();
        if (code === '') {
          // 如果是空,则显示占位符
          this.$emit('input', '');
          codeMirror.setValue(this.placeholder);
        } else if (compare(code, this.placeholder)) {
          // 失去焦点的时候判断是否是占位符,如果是占位符则清除placeholder
          codeMirror.setValue('');
        } else {
          codeMirror.setValue(code);
          // 失去焦点向上级发送事件并把新值传递给父组件处理
          this.$emit('input', code);
        }
      });
    },
    initValue(codeMirror) {
      // 判断是否有值,如果有值则设置值,如果没有则将占位符填充
      if (this.codeStr) {
        codeMirror.setValue(this.codeStr);
      } else {
        codeMirror.setValue(this.placeholder);
      }
    }
  }
};
</script>

autoRefresh.js

import _CodeMirror from 'codemirror/lib/codemirror';

const CodeMirror=window.CodeMirror || _CodeMirror

function stopListening(_cm, state) {
  clearTimeout(state.timeout)
  CodeMirror.off(window, "mouseup", state.hurry)
  CodeMirror.off(window, "keyup", state.hurry)
}

function startListening(cm, state) {
  function check() {
    if (cm.display.wrapper.offsetHeight) {
      stopListening(cm, state)
      if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
        cm.refresh()
    } else {
      state.timeout = setTimeout(check, state.delay)
    }
  }
  state.timeout = setTimeout(check, state.delay)
  state.hurry = function() {
    clearTimeout(state.timeout)
    state.timeout = setTimeout(check, 50)
  }
  CodeMirror.on(window, "mouseup", state.hurry)
  CodeMirror.on(window, "keyup", state.hurry)
}
CodeMirror.defineOption("autoRefresh", false, (cm, val) => {
  if (cm.state.autoRefresh) {
    stopListening(cm, cm.state.autoRefresh)
    cm.state.autoRefresh = null
  }
  if (val && cm.display.wrapper.offsetHeight == 0)
    startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
})

使用

<SkyCodeMirror
      :code-str="value"
      :m-width="mWidth"
      :m-height="mHeight"
      :placeholder="placeholder"
      @input="val => onChange(val, this)"
    />

效果图

CodeMirror(代码编辑器)vue使用及placeholder实现_第1张图片

你可能感兴趣的:(自定义组件,开发问题,vue.js,javascript,编辑器)