提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
<template>
<div ref="monacoEditor" id="monacoEditor" :style="style"></div>
</template>
<script setup>
import { nextTick, onMounted, ref, watch, onBeforeUnmount } from "vue";
import * as monaco from "monaco-editor";
const props = defineProps({
modelValue: {},
style: {},
readOnly: {},
language: {},
content: {},
});
const emit = defineEmits(["update:modelValue"]);
const monacoEditor = ref();
let editor;
const init = () => {
/**
* @param wordWrap 自动换行,注意大小写
*/
editor = monaco.editor.create(monacoEditor.value, {
automaticLayout: true,
value: props.modelValue,
readOnly: props.readOnly,
theme: "vs-dark",
language: props.language,
wordWrap: "on",
wrappingIndent: "indent",
});
// 监听值的变化
editor.onDidChangeModelContent(() => {
emit("update:modelValue", editor.getValue());
});
};
onMounted(() => {
init();
});
watch(
() => props.language,
(nv, ov) => {
monaco.editor.setModelLanguage(editor.getModel(), nv);
}
);
function updateValue() {
setTimeout(() => {
editor.setValue(props.modelValue);
}, 200);
}
watch(
() => props.language,
(newValue) => {
monaco.editor.setModelLanguage(editor.getModel(), newValue);
}
);
defineExpose({ updateValue });
</script>
<style></style>
ps:在比较过程中,支持在右侧的进行文件编辑。可通过界面顶部操作栏,查看当前修改个数(实时更改)。
当前修改处,可通过点击下一个,上一个跳转。当用户选择某行,当前修改处也会发生变化,
需要注意的是,如果当前选中行,不在修改的范围内,则显示0,点击跳转按钮,将跳转到离当前最近的一个修改,并且标识当前处于第几个修改
<template>
<div class="monaco-diff-box">
<div class="layout-start operate">
<div style="width: 50%">{{ leftText }}</div>
<div style="width: 10%">{{ rightText }}</div>
<div class="layout-end" style="width: 40%">
<span
>发现 <span class="config-diff-count">{{ diffCount }}</span
> 处修改</span
>
<span
>,当前第 <span class="config-diff-count">{{
curDiffCount || 0
}}</span
> 处 </span
>
<span
title="上一个"
v-debounce-click="
() => {
exeCommand('goPrevDiff');
}
"
class="diffJump"
>
<el-icon><CaretLeft /></el-icon>
上一个
</span>
<span
title="下一个"
v-debounce-click="
() => {
exeCommand('goNextDiff');
}
"
class="diffJump"
>
下一个
<el-icon><CaretRight /></el-icon>
</span>
</div>
</div>
<div ref="monacoDiff" id="monacoDiff" :style="style"></div>
</div>
</template>
<script setup>
import {
nextTick,
onMounted,
ref,
watch,
onBeforeUnmount,
reactive,
computed,
} from "vue";
import * as monaco from "monaco-editor";
const props = defineProps({
newCode: {},
oldCode: {},
params: {},
language: {},
});
let leftText = ref(props.params.leftText || "修改前");
let rightText = ref(props.params.rightText || "修改后");
const monacoDiff = ref();
const lineChangesDataList = ref([]);
// 当前一共有多少处修改
let diffCount = computed(() => {
return lineChangesDataList.value.length;
});
// 当前cursor指示的几处修改
let curDiffCount = ref(1);
var editor = null;
var decorations = null;
var navi;
var lineChangesDataMap = new Map();
const init = () => {
editor = monaco.editor.createDiffEditor(monacoDiff.value, {
automaticLayout: true,
readOnly: false,
wordWrap: "on",
theme: "vs",
wrappingIndent: "indent",
bracketPairColorization: true,
diffCodeLens: true,
experimental: {
collapseUnchangedRegions: true, // 折叠未更改区域
},
enableSplitViewResizing: false, // 允许用户调整差异编辑器拆分视图的大小。默认为 true。
});
let originalModel = monaco.editor.createModel(props.oldCode, props.language);
let modifiedModel = monaco.editor.createModel(props.newCode, props.language);
editor.setModel({
original: originalModel,
modified: modifiedModel,
});
// decorations = editor.createDecorationsCollection([
// {
// range: new monaco.Range(3, 1, 3, 1),
// options: {
// isWholeLine: true,
// className: "myContentClass",
// glyphMarginClassName: "myGlyphMarginClass",
// },
// },
// ]);
navi = monaco.editor.createDiffNavigator(editor, {
followsCaret: true,
ignoreCharChanges: true,
});
};
onMounted(() => {
init();
setTimeout(() => {
editor.onDidUpdateDiff((val) => {
lineChangesDataList.value = editor.getLineChanges();
lineChangesDataList.value.forEach((item, index) => {
if (item.modifiedEndLineNumber == item.modifiedStartLineNumber) {
lineChangesDataMap.set(item.modifiedStartLineNumber, index + 1);
} else {
for (
let i = item.modifiedStartLineNumber;
i <= item.modifiedEndLineNumber;
i++
) {
lineChangesDataMap.set(i, index + 1);
}
}
});
curDiffCount.value = lineChangesDataMap.get(
editor.getPosition().lineNumber
);
});
lineChangesDataList.value = editor.getLineChanges();
lineChangesDataList.value.forEach((item, index) => {
if (item.modifiedEndLineNumber == item.modifiedStartLineNumber) {
lineChangesDataMap.set(item.modifiedStartLineNumber, index + 1);
} else {
for (
let i = item.modifiedStartLineNumber;
i <= item.modifiedEndLineNumber;
i++
) {
lineChangesDataMap.set(i, index + 1);
}
}
});
editor.getModifiedEditor().onMouseDown((e) => {
lineChangesDataList.value = editor.getLineChanges();
lineChangesDataList.value.forEach((item, index) => {
if (item.modifiedEndLineNumber == item.modifiedStartLineNumber) {
lineChangesDataMap.set(item.modifiedStartLineNumber, index + 1);
} else {
for (
let i = item.modifiedStartLineNumber;
i <= item.modifiedEndLineNumber;
i++
) {
lineChangesDataMap.set(i, index + 1);
}
}
});
curDiffCount.value = lineChangesDataMap.get(e.target.position.lineNumber);
});
editor.getOriginalEditor().onMouseDown((e) => {
lineChangesDataList.value = editor.getLineChanges();
lineChangesDataList.value.forEach((item, index) => {
if (item.modifiedEndLineNumber == item.modifiedStartLineNumber) {
lineChangesDataMap.set(item.modifiedStartLineNumber, index + 1);
} else {
for (
let i = item.modifiedStartLineNumber;
i <= item.modifiedEndLineNumber;
i++
) {
lineChangesDataMap.set(i, index + 1);
}
}
});
curDiffCount.value = lineChangesDataMap.get(e.target.position.lineNumber);
});
}, 200);
});
/**
* @desc 跳转修改处
* @cmd string
* goNextDiff 前进异步
* goPrevDiff 后退一步
*/
const exeCommand = (cmd) => {
let arr = Array.from(lineChangesDataMap.keys());
let positionIndex;
let lineNumber = editor.getPosition().lineNumber;
let hasNewNum = false;
if (arr.indexOf(lineNumber) == -1) {
hasNewNum = true;
arr.push(lineNumber);
arr = arr.sort((a, b) => {
return a - b;
});
}
positionIndex = arr.indexOf(lineNumber);
if (cmd === "goNextDiff") {
setTimeout(() => {
//下一步
if (
curDiffCount.value == lineChangesDataList.value.length ||
(hasNewNum && arr[arr.length - 1] == lineNumber)
) {
curDiffCount.value = 1;
} else {
curDiffCount.value = lineChangesDataMap.get(arr[positionIndex + 1]);
}
navi.next();
}, 300);
} else if (cmd === "goPrevDiff") {
setTimeout(() => {
//上一步
if (curDiffCount.value == 1 || (hasNewNum && arr[0] == lineNumber)) {
curDiffCount.value = lineChangesDataList.value.length;
} else {
curDiffCount.value = lineChangesDataMap.get(arr[positionIndex - 1]);
}
nextTick(() => {
navi.previous();
});
});
}
};
/**
* @desc 获取最新编辑数据
*/
const getValue = () => {
return editor.getModel().modified.getValue();
}
watch(
() => props.language,
(nv, ov) => {
// monaco.editor.setModelLanguage(editor.getModel(), nv);
}
);
defineExpose({
getValue,
});
</script>
<style lang="less">
.monaco-diff-box {
height: 100%;
.operate {
height: 36px;
.config-diff-count {
color: #ff5722;
}
.diffJump {
cursor: pointer;
}
}
#monacoDiff {
flex: 1;
height: calc(100% - 36px);
.monaco-editor .line-numbers.active-line-number {
color: #ff5722;
}
}
}
</style>
待续…
代码如下(示例):
<template>
<v-ace-editor
v-model:value="modelValue"
@init="init"
lang="json"
:theme="theme"
:options="options"
:readonly="readonly"
:style="style"
/>
</template>
<script setup>
import { VAceEditor } from "vue3-ace-editor";
import "ace-builds/webpack-resolver";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-chrome";
import "ace-builds/src-noconflict/ext-language_tools";
const props = defineProps({
modelValue: {},
theme: {},
options: {},
readonly: {},
//自定义行内样式
style: {},
})
</script>
<style>
</style>
<ace-editor
v-model:value="tempFlow.textareashow"
@init="initFail"
lang="json"
:theme="aceConfig.theme"
:options="aceConfig.options"
:readonly="aceConfig.readOnly"
class="ace-editor"
/>
待续…
<template>
<div class="config-diff">
<div class="config-diff-title">
<div class="layout-start">
<div style="width: 50%">{{ leftText }}</div>
<div style="width: 10%">{{ rightText }}</div>
<div class="layout-end" style="width: 40%">
<span
>发现 <span class="config-diff-count">{{ diffCount }}</span
> 处修改</span
>
<span
>,当前第 <span class="config-diff-count">{{
curDiffCount
}}</span
> 处</span
>
<span
title="上一个"
v-debounce-click="
() => {
exeCommand('goPrevDiff');
}
"
class="diffJump"
>
<el-icon><CaretLeft /></el-icon>
上一个
</span>
<span
title="下一个"
v-debounce-click="
() => {
exeCommand('goNextDiff');
}
"
class="diffJump"
>
下一个
<el-icon><CaretRight /></el-icon>
</span>
</div>
</div>
</div>
<div class="merge-view-main">
<div class="file-editor" id="config-diff-view" ref="configDiffView"></div>
</div>
</div>
</template>
<script setup>
import { ref, getCurrentInstance, onMounted, watch } from "vue";
import _ from "lodash";
// 引入全局实例
import CodeMirror from "codemirror";
// 核心样式
import "codemirror/lib/codemirror.css";
// 引入主题后还需要在 options 中指定主题才会生效
import "codemirror/theme/idea.css";
// 需要引入具体的语法高亮库才会有对应的语法高亮效果
// codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
// 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/css/css.js";
import "codemirror/mode/xml/xml.js";
import "codemirror/mode/shell/shell.js";
import "codemirror/mode/sql/sql.js";
//代码补全提示
import "codemirror/addon/hint/anyword-hint.js";
import "codemirror/addon/hint/css-hint.js";
import "codemirror/addon/hint/html-hint.js";
import "codemirror/addon/hint/javascript-hint.js";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/sql-hint.js";
import "codemirror/addon/hint/xml-hint.js";
//代码版本差异比较
import "codemirror/addon/merge/merge.js";
import "codemirror/addon/merge/merge.css";
import DiffMatchPatch from "diff-match-patch";
window.diff_match_patch = DiffMatchPatch;
window.DIFF_DELETE = -1;
window.DIFF_INSERT = 1;
window.DIFF_EQUAL = 0;
const props = defineProps({
newCode: {},
oldCode: {},
params: {},
});
const { proxy } = getCurrentInstance();
//文件后缀和codemirror模式
const FILE_POSTFIX = {
xml: "application/xml",
json: "application/json",
txt: "text/html",
lua: "text/x-lua",
py: "text/x-python",
js: "text/javascript",
sh: "text/x-sh",
other: "text/x-textile",
};
let configDiffView = ref(null);
var dv;
// 当前一共有多少处修改
let diffCount = ref(0);
// 当前cursor指示的几处修改
let curDiffCount = ref(0);
let newCode = "";
let oldCode = "";
let leftText = ref(props.params.leftText || "修改前");
let rightText = ref(props.params.rightText || "修改后");
const postfix = proxy.$commonSvc.getFilePostfix(props.params.name);
const mode = FILE_POSTFIX[postfix] || FILE_POSTFIX.other;
function initUI(target) {
if (oldCode == null) return;
target.innerHTML = "";
dv = CodeMirror.MergeView(target, {
value: newCode,
origLeft: oldCode,
orig: null,
lineNumbers: true, //显示行号
lineWrapping: true,
readOnly: false,
mode: mode,
autofocus: true,
foldGutter: true, //代码折叠
highlightDifferences: "highlight", //有差异的地方是否高亮
collapseIdentical: true,
connect: null,
});
setTimeout(function () {
dv.editor().refresh();
dv.leftOriginal() && dv.leftOriginal().refresh();
}, 500);
var diffs = dv.leftChunks();
diffCount.value = (diffs && diffs.length) || 0;
curDiffCount.value = 0;
}
/**
* @desc exeCommand 执行codemirror mergeview的命令类型
* @param {*} cmd
* 前进一步(goNextDiff) or
* 后退异步(goPrevDiff)
*/
const exeCommand = (cmd) => {
if (diffCount.value == 0) {
return;
} else {
return new Promise((resolve, reject) => {
if (dv) {
if (cmd === "goNextDiff") {
//下一步
if (curDiffCount.value < diffCount.value) {
++curDiffCount.value;
} else {
curDiffCount.value = 1;
}
} else if (cmd === "goPrevDiff") {
//上一步
if (curDiffCount.value > 1) {
curDiffCount.value--;
} else {
curDiffCount.value = diffCount.value;
}
}
if (curDiffCount.value === 0) return;
// 延时,等待diffView刷新后,在定位,存在一定的误差,主要在于不确定diffView刷新需要的时间
setTimeout(function () {
proxy.$commonSvc.highlightCodeMirror(
configDiffView.value,
curDiffCount.value
);
}, 300);
}
});
}
};
/**
* @desc getMergeConfig
*/
const getMergeConfig = () => {
if (!dv) {
return;
}
var edit = dv.edit;
if (!edit) {
return;
}
return edit.getValue();
};
onMounted(() => {
newCode = props.newCode;
oldCode = props.oldCode;
var target = configDiffView.value;
initUI(target);
});
watch(
() => [props.newCode, props.params],
(newValue) => {
newCode = props.newCode;
oldCode = props.oldCode;
var target = configDiffView.value;
initUI(target);
},
{
deep: true,
}
);
defineExpose({
getMergeConfig,
});
</script>
<style lang="less" scoped>
.config-diff {
height: 100%;
display: flex;
flex-direction: column;
padding: 0 16px;
.config-diff-title {
height: 36px;
.config-diff-count {
color: #ff5722;
}
}
.merge-view-main {
flex: 1;
.file-editor {
height: 600px;
.CodeMirror-merge,
.CodeMirror {
z-index: 88888;
height: 520px !important;
}
}
.light-cursor {
background: #b390f7;
}
}
@media (min-width: 760px) {
.merge-view-main {
.file-editor {
.CodeMirror-merge,
.CodeMirror {
height: 290px !important;
}
}
}
}
@media (min-width: 1440px) {
.merge-view-main {
.file-editor {
.CodeMirror-merge,
.CodeMirror {
height: 520px !important;
}
}
}
}
.dev-test {
.cm-s-blackboard.CodeMirror,
.CodeMirror-merge-copybuttons-right,
svg,
.CodeMirror-merge-2pane .CodeMirror-merge-gap {
height: 100%;
}
}
.merge-event {
.CodeMirror-merge-copy {
pointer-events: auto !important;
}
}
}
.diffJump {
cursor: pointer;
}
</style>
/**
* @desc codemirror merge next和pre 高亮
* @param codeWrap {{string|Dom Element}} 需要检查的code所属的一个dom元素,目的缩小查询范围
* @param lineNumber {{number}} 需要高亮的行
*/
highlightCodeMirror(codeWrap, curDiffCount) {
if (!codeWrap) {
return false;
}
var lines_left = $(".CodeMirror-merge-left", $(codeWrap))
.find(".CodeMirror-linebackground")
.get();
var lines_right = $(".CodeMirror-merge-editor", $(codeWrap))
.find(".CodeMirror-linebackground")
.get();
var merge_left = $(".CodeMirror-merge-left", $(codeWrap))
.find(".CodeMirror-merge-l-chunk")
.get();
var merge_right = $(".CodeMirror-merge-editor", $(codeWrap))
.find(".CodeMirror-merge-l-chunk")
.get();
var lineNumber_left;
var lineNumber_right;
var merge_left_end = $(".CodeMirror-merge-left", $(codeWrap)).find(
".CodeMirror-merge-l-chunk-end"
);
var merge_right_end = $(".CodeMirror-merge-editor", $(codeWrap)).find(
".CodeMirror-merge-l-chunk-end"
);
var lineNumber_left_end = merge_left_end
.eq(curDiffCount - 1)
.parent()
.find(".CodeMirror-linenumber")
.text();
var lineNumber_right_end = merge_right_end
.eq(curDiffCount - 1)
.parent()
.find(".CodeMirror-linenumber")
.text();
/**
* @desc 定位每次修改高亮的起始和结束位置
*/
for (var i = lines_left.length - 1; i >= 0; i--) {
var temp = $(lines_left[i]).parent().find(".CodeMirror-linenumber");
var value = parseInt($(temp).text());
var value_end = parseInt(lineNumber_left_end);
if (value <= value_end) {
if (
value < value_end &&
$(lines_left[i]).attr("class").indexOf("-end") != -1
) {
break;
}
if ($(lines_left[i]).attr("class").indexOf("-start") != -1) {
lineNumber_left = $(temp).text();
}
}
}
for (var i = lines_right.length - 1; i >= 0; i--) {
var temp = $(lines_right[i]).parent().find(".CodeMirror-linenumber");
var value = parseInt($(temp).text());
var value_end = parseInt(lineNumber_right_end);
if (value <= value_end) {
if (
value < value_end &&
$(lines_right[i]).attr("class").indexOf("-end") != -1
) {
break;
}
if ($(lines_right[i]).attr("class").indexOf("-start") != -1) {
lineNumber_right = $(temp).text();
}
}
}
/**
* @desc 注入样式
*/
merge_left.forEach(function (item) {
var temp = $(item).parent().find(".CodeMirror-linenumber");
if (
lineNumber_left &&
parseInt($(temp).text()) >= parseInt(lineNumber_left) &&
parseInt($(temp).text()) <= parseInt(lineNumber_left_end)
) {
$(item).addClass("light-cursor");
} else {
$(item).removeClass("light-cursor");
}
});
merge_right.forEach(function (item) {
var temp = $(item).parent().find(".CodeMirror-linenumber");
if (
lineNumber_right &&
parseInt($(temp).text()) >= parseInt(lineNumber_right) &&
parseInt($(temp).text()) <= parseInt(lineNumber_right_end)
) {
$(item).addClass("light-cursor");
} else {
$(item).removeClass("light-cursor");
}
});
},
提示:这里对文章进行总结:
记录web在线编辑器的~