index.vue 2.73 KB
<script lang="ts" setup>
  import { ref, watch } from 'vue';
  import JSONEditor, { JSONEditorOptions } from 'jsoneditor';
  import 'jsoneditor/dist/jsoneditor.min.css';
  import { unref } from 'vue';
  import { onMounted } from 'vue';
  import { computed } from '@vue/reactivity';
  import { onUnmounted } from 'vue';

  enum EventEnum {
    UPDATE_VALUE = 'update:value',
    CHANGE = 'change',
    BLUR = 'blur',
    FOCUS = 'focus',
  }

  const props = withDefaults(
    defineProps<{
      value?: string;
      options?: JSONEditorOptions;
    }>(),
    {
      options: () =>
        ({
          mode: 'code',
          mainMenuBar: false,
          statusBar: false,
        } as JSONEditorOptions),
    }
  );

  const emit = defineEmits<{
    (e: EventEnum.UPDATE_VALUE, value: any, instance?: JSONEditor): void;
    (e: EventEnum.CHANGE, value: any, instance?: JSONEditor): void;
    (e: EventEnum.BLUR, event: Event, instance?: JSONEditor): void;
    (e: EventEnum.FOCUS, event: Event, instance?: JSONEditor): void;
  }>();

  const jsonEditorElRef = ref<Nullable<any>>();

  const editoreRef = ref<JSONEditor>();

  const isFocus = ref(false);

  const handleChange = (value: any) => {
    emit(EventEnum.UPDATE_VALUE, value, unref(editoreRef));
    emit(EventEnum.CHANGE, value, unref(editoreRef));
  };

  const handleEmit = (event: Event, key: EventEnum) => {
    emit(key as EventEnum[keyof EventEnum], event, unref(editoreRef));
  };

  const getOptions = computed(() => {
    const { options } = props;
    return {
      ...options,
      onChangeText: handleChange,
      onBlur: (event: Event) => {
        isFocus.value = false;
        handleEmit(event, EventEnum.BLUR);
      },
      onFocus: (event: Event) => {
        isFocus.value = true;
        handleEmit(event, EventEnum.FOCUS);
      },
    } as JSONEditorOptions;
  });

  const initialize = () => {
    editoreRef.value = new JSONEditor(unref(jsonEditorElRef), unref(getOptions));
  };

  watch(
    () => props.value,
    (target) => {
      if (unref(isFocus)) return;
      unref(editoreRef)?.setText(target || '');
    },
    {
      immediate: true,
    }
  );

  const get = (): string => {
    return unref(editoreRef)?.getText() || '';
  };

  const set = (data: any) => {
    return unref(editoreRef)?.set(data);
  };

  onMounted(() => {
    initialize();
    unref(editoreRef)?.setText(props.value || '');
  });

  onUnmounted(() => {
    unref(editoreRef)?.destroy();
  });

  defineExpose({
    get,
    set,
  });
</script>

<template>
  <div class="p-2 bg-gray-200">
    <div ref="jsonEditorElRef" class="jsoneditor"></div>
  </div>
</template>

<style lang="less" scoped>
  .jsoneditor {
    border: none !important;

    :deep(.jsoneditor) {
      border: none !important;
    }
  }
</style>