<template>
<div class="sqleditor">
<textarea ref="codeMirror" class="sqleditor-top"></textarea>
</div>
</template>
import {
ref,
reactive,
computed,
watch,
nextTick,
defineEmits,
onMounted,
onUnmounted,
markRaw,
defineExpose
} from "vue";
// 核心样式
import "codemirror/lib/codemirror.css";
// 引入主题后还需要在 options 中指定主题才会生效
import "codemirror/addon/display/fullscreen.css"; // 全屏显示编辑器
import "codemirror/addon/display/fullscreen.js"; // 全屏显示编辑器
import "codemirror/theme/cobalt.css";
import "codemirror/theme/eclipse.css";
import "codemirror/theme/ayu-dark.css";
import "codemirror/theme/idea.css";
import "codemirror/theme/solarized.css";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/sql-hint.js";
import "codemirror/addon/selection/active-line.js";
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/mode/sql/sql";
import CodeMirror from "codemirror";
//接收父组件传过来的数据
const props = defineProps({
runLoading: {
type: Boolean,
default: false,
},
czshow: {
type: Object,
default: "",
},
dataValue: {
type: String,
default: "",
},
});
//监听数据的变化
watch(
() => props.dataValue,
(val) => {
setValue(val);//设置textarea的值
markText();//修改需要标记的数据
}
);
const emit = defineEmits();
const sqlEditor = ref(null);
const codes = ref("");
onMounted(() => {
init();
setSize();
markText();
});
const codeMirror = ref(null);
function init() {
sqlEditor.value = markRaw(
CodeMirror.fromTextArea(codeMirror.value, {
tabSize: 2,
styleActiveLine: false,
lineNumbers: true,
line: false,
mode: "text/x-sql",
theme: "solarized",
lineWrapping: true,
hintOptions: {
// 自定义提示选项
completeSingle: false, // 当匹配只有一项的时候是否自动补全
},
})
);
setValue(props.dataValue);
editorEvents();
}
function setValue(sql) {
sqlEditor.value.setValue(sql);
}
function setSize(width = "500px", height = "300px") {
sqlEditor.value.setSize(width, height);
}
function editorEvents() {
// 设置代码提示
sqlEditor.value.on("keyup", (cm, event) => {
if (event.keyCode >= 65 && event.keyCode <= 90) {
cm.showHint();
}
});
// 代码输入的双向绑定
sqlEditor.value.on("change", (editor) => {
// 这里要用多一个载体去获取值,不然会重复赋值卡顿
console.log(editor, "editor");
codes.value = editor.getValue();
if (emit) {
emit("changNameList", codes.value);
}
});
}
const marks = ref();
function markText() {
const param = sqlEditor.value.getValue()
// 拆分有特定标识的字符串
const on = param.match(/\${(.+?)\}/g);
// 已拆分的字符串去重
let his = Array.from(new Set(on));
// 去重之后的数组跟传入的字符串做对比 然后进行标记
marks.value = [];
let index = 0;
sqlEditor.value?.eachLine((line) => {
his.forEach(i=>{
let tabIndex = getStrPositions(param,i)
tabIndex.forEach(item=>{
let text = document.createElement("span");
text.className = 'cm-field';
text.innerText = i;
const mark = sqlEditor.value?.markText(
{ line: index, ch: item },
{ line: index, ch: item + i.length },
{
atomic: true, selectRight: true,
replacedWith: text,
}
);
mark && marks.value.push(mark);
})
})
index++;
});
}
function insertParamToCodeMirror(param) {
const pos1 = sqlEditor.value.getCursor()
const pos2 = {}
pos2.line = pos1.line
pos2.ch = pos1.ch
sqlEditor.value.replaceRange(param, pos2)
markText()
}
// 获取字符串在字符中所有的位置
function getStrPositions(str, subStr) {
var indexs = [];
var string = str;
while (true) {
var index = string.lastIndexOf(subStr);
if (index != -1) {
string =
string.substr(0, index) + string.substr(index + subStr.length, string.length);
indexs.push(index);
} else {
break;
}
}
return indexs;
}
最终执行效果类似这种