编辑区域和预览区域¶
| Text Only | |
|---|---|
一、MarkdownContainer¶
MarkdownContainer.vue 脚本参考
编辑侧进行了三个区域划分,最上面部分是编辑器工具栏,增加常用的格式和图标等的输入。如标题、字体、对齐、数学公式、列表(有序、无序)、超链接、表格、Emoji、特殊字符、mermaid绘图、Plantuml绘图。
下面的部分分为两部分,左侧作为编辑器区域,进行markdown的编辑,右侧增加预览区域。
中间有个分割部分,可以鼠标拖动,以修改编辑区和预览区的显示百分比。
另外,在视图部分,增加编辑框部分的显示模式。编辑器模式、预览模式、编辑/预览模式。
二、编辑器组件¶
这里使用的是monaco-editor编辑器,嵌入vue组件,组件监听编辑器内容变化,然后将新的内容实时渲染到预览区域
MarkdownEditComponent.vue 脚本参考
TypeScript   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
    v-show="isShowEditArea"
    id="md-edit-component"
    class="md-edit-component"
    :style="{ width: monacoEditorWidth }"
  >
    <MdMonacoEdit
      v-model="markdownEditorCode"
      :code="initialCodeContent"
      :editor-area-width="monacoEditorWidthPx"
      @update:code="handleMarkdownCodeUpdate"
    />
  </div>
  <div
    v-show="isShowResizer"
    id="resizer-md"
    class="resizer-md"
    :style="{ left: resizerLeft }"
    @mousedown="onEditorResizerMouseDown($event)"
  ></div>
  <div
    v-show="isShowPreviewArea"
    id="md-preview"
    class="md-preview"
    :style="{ width: editPreviewAreaWidth, left: editPreviewAreaLeft }"
  >
    <MdPreview :editor-content="markdownEditorContent" />
  </div>
</template>
function onEditorResizerMouseDown(e: MouseEvent) {
  editorMouseStart = e.clientX
  window.addEventListener('mousemove', onEditorMouseMove)
  window.addEventListener('mouseup', onEditorMouseUp)
}
// 编辑器大小调整逻辑(百分比)
function onEditorMouseMove(e: MouseEvent) {
  const windowWidthValue = parseInt(windowWidth.value.replace('px', ''), 10)
  const moveX = e.clientX - editorMouseStart
  // 将当前百分比宽度转换为像素值
  const currentWidthPx =
    (parseFloat(monacoEditorWidth.value.replace('%', '')) / 100) * windowWidthValue
  const newWidthPx = currentWidthPx + moveX
  // 转换为百分比
  let newWidthPercent = pxToPercent(newWidthPx, windowWidthValue)
  // 限制最小和最大宽度(百分比)
  const minWidthPercent = '20%'
  const maxWidthPercent = '70%'
  if (newWidthPercent > maxWidthPercent) {
    newWidthPercent = maxWidthPercent
  } else if (newWidthPercent < minWidthPercent) {
    newWidthPercent = minWidthPercent
  }
  // 更新 Monaco Editor 宽度
  monacoEditorWidth.value = newWidthPercent
  editorMouseStart = e.clientX
}
function onEditorMouseUp() {
  window.removeEventListener('mousemove', onEditorMouseMove)
  window.removeEventListener('mouseup', onEditorMouseUp)
}
function handleMarkdownCodeUpdate(newValue: string) {
  window.electron.ipcRenderer.send('update-select-file-content', newValue)
  markdownEditorContent.value = newValue
}
function onHandleNewContent(content: string) {
  if (content) {
    // 编辑区域显示时,传入
    if (isShowEditArea.value) {
      initialCodeContent.value = content
    }
    // 预览模式、编辑器/预览模式,才进行渲染
    if (isShowPreviewArea.value) {
      handleMarkdownCodeUpdate(content)
    }
  } else {
    // console.log('content bull')
    handleMarkdownCodeUpdate('\r\n')
  }
}
window.electron.ipcRenderer.on('show-selected-file-context', (_, content) => {
  EventBus.$emit('plugin-tools-container-show', false)
  onHandleNewContent(content)
})
window.electron.ipcRenderer.on('monaco-insert-writing-templates', (_, fileContent: string) => {
  onHandleNewContent(fileContent)
})
function onHandleEditorShow(edit: boolean, preview: boolean) {
  isShowEditArea.value = edit
  isShowPreviewArea.value = preview
  if (edit && preview) {
    isShowResizer.value = true
    monacoEditorWidth.value = '50%'
  } else {
    isShowResizer.value = false
    if (edit) {
      monacoEditorWidth.value = '100%'
    } else {
      monacoEditorWidth.value = '0%'
    }
  }
}
window.electron.ipcRenderer.on('markdown-edit-model', () => {
  onHandleEditorShow(true, false)
})
window.electron.ipcRenderer.on('markdown-preview-model', () => {
  onHandleEditorShow(false, true)
})
window.electron.ipcRenderer.on('markdown-edit-preview-model', () => {
  onHandleEditorShow(true, true)
})
这里面增加了一些样式控制的东西,可以动态调整编辑区域和预览区域
三、预览区域¶
MarkdownPreviewComponent.vue 脚本参考
这里使用markdown-it进行渲染,因为markdown语法本身是支持html语言的,所以遇到一些特殊的或者自定义的格式,这里就在渲染之前,进行预渲染。比如mermaid绘图、公式、路径、链接、自定义的格式、特殊的字体等。
预渲染之后,再使用markdown-it进行渲染,渲染结束后,再进行后渲染,这里对渲染之后的html再进行特殊的处理,只是这里的会涉及的少一些。

四、效果¶
