monaco-editor.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
  2. import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution';
  3. import beautifier from './json-beautifier'
  4. function noop() { }
  5. export { monaco };
  6. export default {
  7. name: 'MonacoEditor',
  8. props: {
  9. diffEditor: { type: Boolean, default: false }, //是否使用diff模式
  10. width: { type: [String, Number], default: '100%' },
  11. height: { type: [String, Number], default: '100%' },
  12. original: String, //只有在diff模式下有效
  13. value: [String, Object],
  14. language: { type: String, default: 'javascript' },
  15. theme: { type: String, default: 'vs' },
  16. readOnly: { type: Boolean, default: false },
  17. options: { type: Object, default() { return {}; } },
  18. editorMounted: { type: Function, default: noop },
  19. editorBeforeMount: { type: Function, default: noop },
  20. keyIndex: { type: String }
  21. },
  22. watch: {
  23. options: {
  24. deep: true,
  25. handler(options) {
  26. this.editor && this.editor.updateOptions(options);
  27. }
  28. },
  29. keyIndex() {
  30. let data = this.value
  31. if (typeof data == 'object') {
  32. data = beautifier(data)
  33. }
  34. if (this.editor && data !== this._getValue()) {
  35. this._setValue(data)
  36. }
  37. },
  38. language() {
  39. if (!this.editor) return;
  40. if (this.diffEditor) { //diff模式下更新language
  41. const { original, modified } = this.editor.getModel();
  42. monaco.editor.setModelLanguage(original, this.language);
  43. monaco.editor.setModelLanguage(modified, this.language);
  44. } else
  45. monaco.editor.setModelLanguage(this.editor.getModel(), this.language);
  46. },
  47. theme() {
  48. this.editor && monaco.editor.setTheme(this.theme);
  49. },
  50. style() {
  51. this.editor && this.$nextTick(() => {
  52. this.editor.layout();
  53. });
  54. },
  55. value(val) {
  56. if (this.editor && val !== this._getValue()) {
  57. this._setValue(val)
  58. }
  59. },
  60. },
  61. computed: {
  62. style() {
  63. return {
  64. width: !/^\d+$/.test(this.width) ? this.width : `${this.width}px`,
  65. height: !/^\d+$/.test(this.height) ? this.height : `${this.height}px`,
  66. position: 'relative'
  67. }
  68. }
  69. },
  70. mounted() {
  71. this.initMonaco();
  72. },
  73. beforeDestroy() {
  74. this.editor && this.editor.dispose();
  75. },
  76. render(h) {
  77. const fullScreen = this.options.fullScreen
  78. return h('div', { class: 'monaco_editor_container', style: this.style }, [
  79. fullScreen ? h('i', { class: 'el-icon-full-screen', style: { width: '1.2em', height: '1.2em', position: 'absolute', left: '0px', top: '0px', zIndex: '1', cursor: 'pointer' }, on: { click: this._handleFullScreen } }) : ''
  80. ])
  81. },
  82. methods: {
  83. initMonaco() {
  84. const { value, language, theme, readOnly, options } = this;
  85. Object.assign(options, this._editorBeforeMount()); //编辑器初始化前
  86. this.editor = monaco.editor[this.diffEditor ? 'createDiffEditor' : 'create'](this.$el, {
  87. value: (typeof value == 'string') ? value : beautifier(value),
  88. language: language,
  89. theme: theme,
  90. readOnly: readOnly,
  91. ...options
  92. });
  93. this.diffEditor && this._setModel(this.value, this.original);
  94. this._editorMounted(this.editor); //编辑器初始化后
  95. },
  96. _handleFullScreen() {
  97. if (this.isMaximum) this.minEditor()
  98. else this.maxEditor()
  99. },
  100. // 放大
  101. maxEditor() {
  102. this.isMaximum = true
  103. let dom = this.$el
  104. this.originSize = {
  105. width: dom.clientWidth,
  106. height: dom.clientHeight
  107. }
  108. dom.classList.add('editor-fullscreen')
  109. this.editor.layout({
  110. height: document.body.clientHeight,
  111. width: document.body.clientWidth
  112. })
  113. document.addEventListener('keyup', (e) => {
  114. if (e.keyCode == 27) {
  115. this.minEditor()
  116. }
  117. })
  118. },
  119. // 缩小
  120. minEditor() {
  121. this.isMaximum = false
  122. let dom = this.$el
  123. dom.classList.remove('editor-fullscreen')
  124. this.editor.layout({
  125. height: this.originSize.height,
  126. width: this.originSize.width
  127. })
  128. document.removeEventListener('keyup', () => { })
  129. },
  130. _getEditor() {
  131. if (!this.editor) return null;
  132. return this.diffEditor ? this.editor.modifiedEditor : this.editor;
  133. },
  134. _setModel(value, original) { //diff模式下设置model
  135. const { language } = this;
  136. const originalModel = monaco.editor.createModel(original, language);
  137. const modifiedModel = monaco.editor.createModel(value, language);
  138. this.editor.setModel({
  139. original: originalModel,
  140. modified: modifiedModel
  141. });
  142. },
  143. _setValue(value) {
  144. let editor = this._getEditor();
  145. if (editor) return editor.setValue(value);
  146. },
  147. _getValue() {
  148. let editor = this._getEditor();
  149. if (!editor) return '';
  150. return editor.getValue();
  151. },
  152. _editorBeforeMount() {
  153. const options = this.editorBeforeMount(monaco);
  154. return options || {};
  155. },
  156. _editorMounted(editor) {
  157. this.editorMounted(editor, monaco);
  158. if (this.diffEditor) {
  159. editor.onDidUpdateDiff((event) => {
  160. const value = this._getValue();
  161. this._emitChange(value, event);
  162. });
  163. } else {
  164. editor.onDidChangeModelContent(event => {
  165. const value = this._getValue();
  166. this._emitChange(value, event);
  167. });
  168. }
  169. },
  170. _emitChange(value, event) {
  171. this.$emit('change', value, event);
  172. this.$emit('input', value);
  173. }
  174. }
  175. }