mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-12-07 02:36:57 +08:00
feat(editor): 代码编辑器支持配置自动高度
This commit is contained in:
parent
8d7c8fa725
commit
8d55d0cd8d
@ -201,7 +201,7 @@ const functionConfig = computed<FormConfig>(() => [
|
|||||||
name: 'content',
|
name: 'content',
|
||||||
type: 'vs-code',
|
type: 'vs-code',
|
||||||
options: inject('codeOptions', {}),
|
options: inject('codeOptions', {}),
|
||||||
height: '500px',
|
autosize: { minRows: 10, maxRows: 30 },
|
||||||
onChange: (formState: FormState | undefined, code: string) => {
|
onChange: (formState: FormState | undefined, code: string) => {
|
||||||
try {
|
try {
|
||||||
// 检测js代码是否存在语法错误
|
// 检测js代码是否存在语法错误
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
...config.options,
|
...config.options,
|
||||||
readOnly: disabled,
|
readOnly: disabled,
|
||||||
}"
|
}"
|
||||||
|
:autosize="config.autosize"
|
||||||
:parse="config.parse"
|
:parse="config.parse"
|
||||||
@save="save"
|
@save="save"
|
||||||
></MagicCodeEditor>
|
></MagicCodeEditor>
|
||||||
|
|||||||
@ -233,7 +233,6 @@ const dataSourceFieldsConfig: FormConfig = [
|
|||||||
{
|
{
|
||||||
name: 'defaultValue',
|
name: 'defaultValue',
|
||||||
text: '默认值',
|
text: '默认值',
|
||||||
height: '200px',
|
|
||||||
parse: true,
|
parse: true,
|
||||||
type: (mForm: FormState | undefined, { model }: any) => {
|
type: (mForm: FormState | undefined, { model }: any) => {
|
||||||
if (model.type === 'number') return 'number';
|
if (model.type === 'number') return 'number';
|
||||||
@ -242,6 +241,7 @@ const dataSourceFieldsConfig: FormConfig = [
|
|||||||
|
|
||||||
return 'vs-code';
|
return 'vs-code';
|
||||||
},
|
},
|
||||||
|
autosize: { minRows: 1, maxRows: 30 },
|
||||||
options: [
|
options: [
|
||||||
{ text: 'true', value: true },
|
{ text: 'true', value: true },
|
||||||
{ text: 'false', value: false },
|
{ text: 'false', value: false },
|
||||||
@ -267,7 +267,7 @@ const jsonFromConfig: FormConfig = [
|
|||||||
type: 'vs-code',
|
type: 'vs-code',
|
||||||
labelWidth: '0',
|
labelWidth: '0',
|
||||||
language: 'json',
|
language: 'json',
|
||||||
height: '600px',
|
autosize: { minRows: 30, maxRows: 50 },
|
||||||
options: inject('codeOptions', {}),
|
options: inject('codeOptions', {}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -96,7 +96,7 @@ const formConfig: FormConfig = [
|
|||||||
language: 'json',
|
language: 'json',
|
||||||
options: inject('codeOptions', {}),
|
options: inject('codeOptions', {}),
|
||||||
defaultValue: '{}',
|
defaultValue: '{}',
|
||||||
height: '400px',
|
autosize: { minRows: 30, maxRows: 50 },
|
||||||
onChange: (formState: FormState | undefined, v: string | any) => {
|
onChange: (formState: FormState | undefined, v: string | any) => {
|
||||||
if (typeof v !== 'string') return v;
|
if (typeof v !== 'string') return v;
|
||||||
return JSON.parse(v);
|
return JSON.parse(v);
|
||||||
|
|||||||
@ -37,12 +37,15 @@
|
|||||||
|
|
||||||
<MagicCodeEditor
|
<MagicCodeEditor
|
||||||
v-if="config.advanced && showCode"
|
v-if="config.advanced && showCode"
|
||||||
height="200px"
|
|
||||||
:init-values="model[name]"
|
:init-values="model[name]"
|
||||||
language="javascript"
|
language="javascript"
|
||||||
:options="{
|
:options="{
|
||||||
readOnly: disabled,
|
readOnly: disabled,
|
||||||
}"
|
}"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 1,
|
||||||
|
maxRows: 20,
|
||||||
|
}"
|
||||||
:parse="true"
|
:parse="true"
|
||||||
@save="save"
|
@save="save"
|
||||||
></MagicCodeEditor>
|
></MagicCodeEditor>
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="`magic-code-editor`">
|
<div :class="`magic-code-editor`">
|
||||||
<Teleport to="body" :disabled="!fullScreen">
|
<Teleport to="body" :disabled="!fullScreen">
|
||||||
<div
|
<div :class="{ 'magic-code-editor-wrapper': true, 'full-screen': fullScreen }" :style="{ height: computeHeight }">
|
||||||
:class="`magic-code-editor-wrapper${fullScreen ? ' full-screen' : ''}`"
|
|
||||||
:style="!fullScreen && height ? `height: ${height}` : '100%'"
|
|
||||||
>
|
|
||||||
<TMagicButton
|
<TMagicButton
|
||||||
v-if="!disabledFullScreen"
|
v-if="!disabledFullScreen"
|
||||||
class="magic-code-editor-full-screen-icon"
|
class="magic-code-editor-full-screen-icon"
|
||||||
@ -20,7 +17,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import { FullScreen } from '@element-plus/icons-vue';
|
import { FullScreen } from '@element-plus/icons-vue';
|
||||||
import { throttle } from 'lodash-es';
|
import { throttle } from 'lodash-es';
|
||||||
import serialize from 'serialize-javascript';
|
import serialize from 'serialize-javascript';
|
||||||
@ -46,6 +43,10 @@ const props = withDefaults(
|
|||||||
autoSave?: boolean;
|
autoSave?: boolean;
|
||||||
parse?: boolean;
|
parse?: boolean;
|
||||||
disabledFullScreen?: boolean;
|
disabledFullScreen?: boolean;
|
||||||
|
autosize?: {
|
||||||
|
minRows?: number;
|
||||||
|
maxRows?: number;
|
||||||
|
};
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
initValues: '',
|
initValues: '',
|
||||||
@ -61,6 +62,58 @@ const props = withDefaults(
|
|||||||
|
|
||||||
const emit = defineEmits(['initd', 'save']);
|
const emit = defineEmits(['initd', 'save']);
|
||||||
|
|
||||||
|
const autoHeight = ref<string>('');
|
||||||
|
|
||||||
|
const computeHeight = computed(() => {
|
||||||
|
if (fullScreen.value) {
|
||||||
|
return '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.height) {
|
||||||
|
return props.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.autosize) {
|
||||||
|
return autoHeight.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '100%';
|
||||||
|
});
|
||||||
|
|
||||||
|
const setAutoHeight = (v = '') => {
|
||||||
|
let lines = Math.max(v.split('\n').length, props.autosize?.minRows || 1);
|
||||||
|
if (v) {
|
||||||
|
if (props.autosize?.maxRows) {
|
||||||
|
lines = Math.min(lines, props.autosize.maxRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取编辑器实际行高,如果编辑器还未初始化则使用默认值
|
||||||
|
let lineHeight = 20;
|
||||||
|
if (vsEditor) {
|
||||||
|
const editorOptions = vsEditor.getOptions();
|
||||||
|
lineHeight = editorOptions.get(monaco.editor.EditorOption.lineHeight) || 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newHeight = `${lines * lineHeight + 10}px`;
|
||||||
|
|
||||||
|
// 只有当高度真正改变时才更新
|
||||||
|
if (autoHeight.value !== newHeight) {
|
||||||
|
autoHeight.value = newHeight;
|
||||||
|
|
||||||
|
// 高度变化后需要重新布局编辑器
|
||||||
|
nextTick(() => {
|
||||||
|
vsEditor?.layout();
|
||||||
|
|
||||||
|
// 确保内容在可视区域内,滚动到顶部
|
||||||
|
if (vsEditor) {
|
||||||
|
vsEditor.setScrollTop(0);
|
||||||
|
vsEditor.revealLine(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const toString = (v: string | any, language: string): string => {
|
const toString = (v: string | any, language: string): string => {
|
||||||
let value: string;
|
let value: string;
|
||||||
if (typeof v !== 'string') {
|
if (typeof v !== 'string') {
|
||||||
@ -110,6 +163,8 @@ const resizeObserver = new globalThis.ResizeObserver(
|
|||||||
const setEditorValue = (v: string | any, m: string | any) => {
|
const setEditorValue = (v: string | any, m: string | any) => {
|
||||||
values.value = toString(v, props.language.toLocaleLowerCase());
|
values.value = toString(v, props.language.toLocaleLowerCase());
|
||||||
|
|
||||||
|
setAutoHeight(values.value);
|
||||||
|
|
||||||
if (props.type === 'diff') {
|
if (props.type === 'diff') {
|
||||||
const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
|
const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
|
||||||
const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
|
const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
|
||||||
@ -147,6 +202,7 @@ const handleKeyDown = (e: KeyboardEvent) => {
|
|||||||
emit('save', props.parse ? parseCode(newValue, props.language) : newValue);
|
emit('save', props.parse ? parseCode(newValue, props.language) : newValue);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
if (!codeEditorEl.value) return;
|
if (!codeEditorEl.value) return;
|
||||||
|
|
||||||
@ -163,8 +219,24 @@ const init = async () => {
|
|||||||
|
|
||||||
if (props.type === 'diff') {
|
if (props.type === 'diff') {
|
||||||
vsDiffEditor = getEditorConfig('customCreateMonacoDiffEditor')(monaco, codeEditorEl.value, options);
|
vsDiffEditor = getEditorConfig('customCreateMonacoDiffEditor')(monaco, codeEditorEl.value, options);
|
||||||
|
|
||||||
|
// 监听diff编辑器内容变化
|
||||||
|
vsDiffEditor.getModifiedEditor().onDidChangeModelContent(() => {
|
||||||
|
// 如果使用 autosize,内容变化时重新计算高度
|
||||||
|
if (props.autosize) {
|
||||||
|
setAutoHeight(getEditorValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
vsEditor = getEditorConfig('customCreateMonacoEditor')(monaco, codeEditorEl.value, options);
|
vsEditor = getEditorConfig('customCreateMonacoEditor')(monaco, codeEditorEl.value, options);
|
||||||
|
|
||||||
|
// 监听编辑器内容变化
|
||||||
|
vsEditor.onDidChangeModelContent(() => {
|
||||||
|
// 如果使用 autosize,内容变化时重新计算高度
|
||||||
|
if (props.autosize) {
|
||||||
|
setAutoHeight(getEditorValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setEditorValue(props.initValues, props.modifiedValues);
|
setEditorValue(props.initValues, props.modifiedValues);
|
||||||
|
|||||||
@ -64,7 +64,7 @@ const fillConfig = (config: FormConfig): FormConfig => [
|
|||||||
name: 'beforeRequest',
|
name: 'beforeRequest',
|
||||||
type: 'vs-code',
|
type: 'vs-code',
|
||||||
parse: true,
|
parse: true,
|
||||||
height: '600px',
|
autosize: { minRows: 10, maxRows: 30 },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -76,7 +76,7 @@ const fillConfig = (config: FormConfig): FormConfig => [
|
|||||||
name: 'afterResponse',
|
name: 'afterResponse',
|
||||||
type: 'vs-code',
|
type: 'vs-code',
|
||||||
parse: true,
|
parse: true,
|
||||||
height: '600px',
|
autosize: { minRows: 10, maxRows: 30 },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -39,6 +39,10 @@ export interface CodeConfig extends FormItem {
|
|||||||
};
|
};
|
||||||
height?: string;
|
height?: string;
|
||||||
parse?: boolean;
|
parse?: boolean;
|
||||||
|
autosize?: {
|
||||||
|
minRows?: number;
|
||||||
|
maxRows?: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CodeLinkConfig extends FormItem {
|
export interface CodeLinkConfig extends FormItem {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user