django-vue3-admin-web/node_modules/json-editor-vue3/lib/json-editor.vue
2025-10-20 21:21:14 +08:00

213 lines
5.7 KiB
Vue

<script>
import JsonEditor from "jsoneditor";
import "jsoneditor/dist/jsoneditor.min.css";
export default {
editor: null,
name: "json-editor-vue",
internalChange: false,
props: {
modelValue: Object | Number | Array,
// https://github.com/josdejong/jsoneditor/blob/master/docs/api.md#configuration-options
options: Object,
currentMode: {
type: String,
default: "code",
},
modeList: {
type: Array,
default: () => ["tree", "code", "form", "text", "view"],
},
// en, es zh-CN, pt-BR, tr, ja, fr-FR, de, ru, ko
language: {
type: String,
default: "en",
},
},
data() {
return {
json: this.modelValue,
expandedModes: ["tree", "view", "form"],
// 全屏处理
isFullScreen: false,
hasLogo: true,
showFullScreen: false,
};
},
watch: {
modelValue: {
immediate: true,
deep: true,
handler(val) {
// 内容变化赋值
if (!this.internalChange) {
this.setEditorContent(val);
this.$nextTick(() => {
this.expandAll();
});
}
},
},
},
mounted() {
this.init();
const logo = document.querySelector(
".jsoneditor-menu .jsoneditor-poweredBy"
);
this.hasLogo = logo && window.getComputedStyle(logo).display !== "none";
this.showFullScreen = true;
},
unmounted() {
this.editor?.destroy();
this.editor = null;
},
methods: {
toggleFullScreen() {
this.isFullScreen = !this.isFullScreen;
this.$nextTick(() => {
const event = new Event("resize");
window.dispatchEvent(event);
});
},
init() {
const { currentMode, modeList, options } = this;
const onChange = () => {
const setJson = (json) => {
this.json = json;
this.$emit("update:modelValue", json);
this.$emit("change", json);
this.internalChange = true;
this.$nextTick(() => {
this.internalChange = false;
});
};
// 兼容一次性删除所有内容
const text = this.editor.getText();
if (!text) {
setJson('');
return;
}
try {
const json = this.editor.get();
setJson(json);
} catch (error) {
// console.log(error);
}
};
const onModeChange = () => {
this.expandAll();
};
const onTextSelectionChange = (start, end, text) => {
this.$emit("textSelectionChange", this.editor, start, end, text);
};
const onSelectionChange = (start, end) => {
this.$emit("selectionChange", this.editor, start, end);
};
const onColorPicker = (parent, color, onChange) => {
this.$emit("colorPicker", this.editor, parent, color, onChange);
};
const onFocus = ({ target }) => {
this.$emit("focus", this.editor, target);
};
const onBlur = ({ target }) => {
this.$emit("blur", this.editor, target);
};
const onValidationError = (errors) => {
this.$emit("validationError", this.editor, errors);
};
const finalOptions = {
...options,
indentation: 2,
language: this.language,
mode: currentMode,
modes: modeList,
onChange,
onModeChange,
onTextSelectionChange,
onSelectionChange,
onColorPicker,
onFocus,
onBlur,
onValidationError,
};
this.editor = new JsonEditor(
this.$refs.jsonEditorVue,
finalOptions,
this.json
);
},
expandAll() {
if (this.expandedModes.includes(this.editor?.getMode())) {
this.editor?.expandAll();
}
},
setEditorContent(value) {
this.editor?.set(value);
},
},
};
</script>
<template>
<div class="container" :class="{ 'full-screen-container': isFullScreen }">
<div ref="jsonEditorVue" class="json-editor-vue" />
<div
class="full-screen"
:class="{
show: showFullScreen,
right: !hasLogo,
}"
@click="toggleFullScreen"
/>
</div>
</template>
<style scoped>
.container {
position: relative;
}
.full-screen-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999999999999;
width: auto !important;
height: auto !important;
}
.json-editor-vue {
width: 100%;
height: 100%;
}
code {
background-color: #f5f5f5;
}
.full-screen {
position: absolute;
display: none;
top: 8px;
right: 110px;
width: 22px;
height: 22px;
border-radius: 2px;
cursor: pointer;
background-size: cover;
background-image: url("data:image/svg+xml,%3Csvg t='1635416254060' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='42247' width='128' height='128'%3E%3Cpath d='M240.8 196l178.4 178.4-45.6 45.6-177.6-179.2-68 68V128h180.8l-68 68z m133.6 408.8L196 783.2 128 715.2V896h180.8l-68-68 178.4-178.4-44.8-44.8zM715.2 128l68 68-178.4 178.4 45.6 45.6 178.4-178.4 68 68V128H715.2z m-65.6 476.8l-45.6 45.6 178.4 178.4-68 68H896V715.2l-68 68-178.4-178.4z' p-id='42248' fill='%23ffffff'%3E%3C/path%3E%3C/svg%3E");
}
.full-screen-container .full-screen {
background-image: url("data:image/svg+xml,%3Csvg t='1635416420969' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='42490' width='128' height='128'%3E%3Cpath d='M142.4 96.8l-44.8 44.8 173.6 174.4-68 68H384V203.2l-67.2 67.2zM752.8 316l173.6-174.4-44.8-44.8-174.4 173.6-67.2-67.2V384h180.8zM270.4 707.2l-169.6 170.4 44.8 49.6 170.4-174.4 68 68V640H203.2zM820.8 640H640v180.8l68-68 170.4 174.4 44.8-49.6-169.6-170.4z' p-id='42491' fill='%23ffffff'%3E%3C/path%3E%3C/svg%3E");
}
.show {
display: block;
}
.right {
right: 15px;
}
.full-screen:hover {
border: 1px solid #d7e6fe;
}
</style>