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/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;
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', () => {
const code = codeMirror.getValue();
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)) {
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)"
/>
效果图