wwf
10 小时以前 a1d7e81859f554f3a53680cc35f0f49bf1f77098
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<template>
  <div ref="jsonEditorContainer" class="json-editor" :style="{ height }"></div>
</template>
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import JSONEditor, { JSONEditorMode, JSONEditorOptions } from 'jsoneditor'
import 'jsoneditor/dist/jsoneditor.min.css'
import { JsonEditorEmits, JsonEditorExpose, JsonEditorProps } from '../types'
 
/** 基于 https://github.com/josdejong/jsoneditor 二次封装组件,提供 JSON 编辑器功能。 */
defineOptions({ name: 'JsonEditor' })
 
const props = withDefaults(defineProps<JsonEditorProps>(), {
  mode: 'view' as JSONEditorMode,
  height: '400px',
  showModeSelection: false,
  showNavigationBar: false,
  showStatusBar: false,
  showMainMenuBar: true
})
 
const emits = defineEmits<JsonEditorEmits>()
const jsonObj = useVModel(props, 'modelValue', emits) as Ref<any>
const jsonEditorContainer = ref<HTMLElement | null>(null)
let jsonEditor: JSONEditor | null = null
 
// 设置默认值
const height = props.height
 
// 初始化JSONEditor
const initJsonEditor = () => {
  if (!jsonEditorContainer.value) return
 
  // 合并默认配置和用户自定义配置
  const options: JSONEditorOptions = {
    mode: props.mode,
    modes: props.showModeSelection
      ? (['tree', 'code', 'form', 'text', 'view', 'preview'] as JSONEditorMode[])
      : undefined,
    navigationBar: props.showNavigationBar,
    statusBar: props.showStatusBar,
    mainMenuBar: props.showMainMenuBar,
    onChange: () => {
      jsonObj.value = jsonEditor?.get()
      emits('change', jsonEditor?.get())
    },
    onValidationError: (errors: any) => {
      emits('error', errors)
    },
    ...props.options
  } as JSONEditorOptions
 
  // 创建JSONEditor实例
  jsonEditor = new JSONEditor(jsonEditorContainer.value, options)
 
  // 设置初始值
  if (jsonObj.value) {
    jsonEditor.set(jsonObj.value)
  }
 
  if (props.mode === 'view') {
    jsonEditor?.expandAll() // 默认展开全部
  }
}
 
// 监听数据变化
watch(
  () => jsonObj.value,
  (newValue) => {
    if (!jsonEditor) return
 
    try {
      // 防止无限循环更新
      const currentJson = jsonEditor.get()
      if (JSON.stringify(currentJson) !== JSON.stringify(newValue)) {
        jsonEditor.update(newValue)
      }
    } catch (error) {
      console.error('JSON更新失败:', error)
    }
  },
  { deep: true }
)
 
// 监听模式变化
watch(
  () => props.mode,
  (newMode) => {
    if (!jsonEditor) return
    try {
      jsonEditor.setMode(newMode)
    } catch (error) {
      console.error('切换模式失败:', error)
    }
  }
)
 
// 生命周期钩子
onMounted(() => {
  initJsonEditor()
})
 
onBeforeUnmount(() => {
  if (jsonEditor) {
    jsonEditor.destroy()
    jsonEditor = null
  }
})
 
// 暴露方法
defineExpose<JsonEditorExpose>({
  // 获取编辑器实例,以便可以调用更多JSONEditor的原生方法
  getEditor: () => jsonEditor
})
</script>
 
<style lang="scss" scoped>
/* 隐藏 Ace 编辑器的 powered by ace 标记 */
:deep(.jsoneditor-menu) {
  /* 隐藏 powered by ace 标记 */
  .jsoneditor-poweredBy {
    display: none !important;
  }
}
</style>