213 lines
5.7 KiB
Vue
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>
|