index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <template>
  2. <div>
  3. <textarea ref="codeMirrorRef"></textarea>
  4. </div>
  5. </template>
  6. <script>
  7. import { ref, onMounted, watch, markRaw, nextTick, computed } from 'vue'
  8. import { getUsingConfig, isJson } from '@cip/utils/util'
  9. import CodeMirror from 'codemirror'
  10. import 'codemirror/lib/codemirror.css'
  11. import 'codemirror/mode/javascript/javascript'
  12. import 'codemirror/mode/xml/xml'
  13. import 'codemirror/mode/sql/sql'
  14. import 'codemirror/addon/hint/show-hint'
  15. import 'codemirror/addon/hint/sql-hint'
  16. import 'codemirror/addon/hint/javascript-hint'
  17. import 'codemirror/addon/hint/show-hint.css'
  18. import 'codemirror/addon/edit/closebrackets'
  19. import 'codemirror/theme/dracula.css'
  20. import 'codemirror/theme/3024-day.css'
  21. export default {
  22. name: 'CipCodeMirror',
  23. props: {
  24. modelValue: [String, Object],
  25. /**
  26. * 可选值: false true 'nocursor'
  27. * nocursor: readonly状态并且不展示光标
  28. */
  29. readonly: {
  30. type: [Boolean, String],
  31. default: false
  32. },
  33. type: {
  34. type: String,
  35. default: 'json'
  36. },
  37. mode: String,
  38. height: {
  39. type: String,
  40. default: 'auto'
  41. },
  42. theme: { // 主题,需要额外引入
  43. type: String,
  44. default: 'dracula'
  45. },
  46. lineNumbers: {
  47. type: Boolean,
  48. default: true
  49. },
  50. indentUnit: {
  51. type: Number,
  52. default: 4
  53. }
  54. },
  55. emits: ['update:modelValue'],
  56. setup (props, { emit }) {
  57. const codeMirrorRef = ref()
  58. const codeMirror = ref()
  59. const _mode = computed(() => getUsingConfig(
  60. props.mode,
  61. props.type === 'json' ? 'application/json' : `text/${props.type}`))
  62. const getCodeMirrorInstance = () => {
  63. const instance = CodeMirror.fromTextArea(codeMirrorRef.value, {
  64. value: formatterValue(props.modelValue),
  65. mode: _mode.value,
  66. theme: props.theme,
  67. indentUnit: props.indentUnit,
  68. lineNumbers: props.lineNumbers,
  69. lineWrapping: false,
  70. readOnly: props.readonly,
  71. singleCursorHeightPerLine: false,
  72. extraKeys: {}
  73. })
  74. instance.setSize(props.width ?? '100%', props.height ?? 'auto')
  75. instance.on('change', (instance, obj) => {
  76. const { origin } = obj
  77. const value = instance.getValue()
  78. codeMirror.value.save()
  79. if (origin !== 'setValue') { // 非setValue导致的更新才emit
  80. emit('update:modelValue', value)
  81. }
  82. })
  83. instance.on('inputRead', function () {
  84. instance.showHint({
  85. completeSingle: false
  86. })
  87. })
  88. return instance
  89. }
  90. const formatterValue = (val) => {
  91. if (props.type === 'json' && val) {
  92. let data = val
  93. if (typeof val === 'string' && isJson(data)) {
  94. data = JSON.parse(data)
  95. }
  96. return JSON.stringify(data, null, 2) ?? ''
  97. } else {
  98. return val
  99. }
  100. }
  101. onMounted(() => {
  102. codeMirror.value = markRaw(getCodeMirrorInstance())
  103. watch(() => props.modelValue, (val, oldVal) => {
  104. const codeMirrorValue = codeMirror.value?.getValue?.()
  105. if (codeMirrorValue === val) return
  106. codeMirror.value.setValue(formatterValue(val) ?? '')
  107. nextTick(() => {
  108. codeMirror.value.refresh()
  109. })
  110. }, {
  111. immediate: true
  112. })
  113. })
  114. return {
  115. codeMirrorRef
  116. }
  117. }
  118. }
  119. </script>