refactor(editor): 重构工具栏动作处理逻辑

将工具栏动作处理逻辑从 useEditor 组合式函数移至 LivePreviewEditor 组件内部,通过事件直接触发动作执行,简化组件间通信并提高代码内聚性。移除 EditorToolbar 组件中对 useEditor 的依赖,改为直接发射 'action' 事件。
This commit is contained in:
cfq 2026-01-26 18:44:59 +08:00
parent 3d31989d4b
commit c4b9aaaaca
3 changed files with 24 additions and 15 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -7,7 +7,7 @@
<template #icon><span style="font-weight: bold; font-size: 14px;">H</span></template> <template #icon><span style="font-weight: bold; font-size: 14px;">H</span></template>
</a-button> </a-button>
<template #overlay> <template #overlay>
<a-menu @click="({ key }) => triggerAction('heading', key)"> <a-menu @click="({ key }) => $emit('action', 'heading', key)">
<a-menu-item :key="1"><span style="font-size: 1.6em; font-weight: bold;">H1 标题</span></a-menu-item> <a-menu-item :key="1"><span style="font-size: 1.6em; font-weight: bold;">H1 标题</span></a-menu-item>
<a-menu-item :key="2"><span style="font-size: 1.4em; font-weight: bold;">H2 标题</span></a-menu-item> <a-menu-item :key="2"><span style="font-size: 1.4em; font-weight: bold;">H2 标题</span></a-menu-item>
<a-menu-item :key="3"><span style="font-size: 1.2em; font-weight: bold;">H3 标题</span></a-menu-item> <a-menu-item :key="3"><span style="font-size: 1.2em; font-weight: bold;">H3 标题</span></a-menu-item>
@ -21,36 +21,36 @@
<a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" /> <a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" />
<!-- 文本样式 --> <!-- 文本样式 -->
<a-button type="text" size="small" @click="triggerAction('bold')" title="加粗 (Ctrl+B)"> <a-button type="text" size="small" @click="$emit('action', 'bold')" title="加粗 (Ctrl+B)">
<template #icon><BoldOutlined /></template> <template #icon><BoldOutlined /></template>
</a-button> </a-button>
<a-button type="text" size="small" @click="triggerAction('italic')" title="斜体 (Ctrl+I)"> <a-button type="text" size="small" @click="$emit('action', 'italic')" title="斜体 (Ctrl+I)">
<template #icon><ItalicOutlined /></template> <template #icon><ItalicOutlined /></template>
</a-button> </a-button>
<a-button type="text" size="small" @click="triggerAction('strike')" title="删除线"> <a-button type="text" size="small" @click="$emit('action', 'strike')" title="删除线">
<template #icon><StrikethroughOutlined /></template> <template #icon><StrikethroughOutlined /></template>
</a-button> </a-button>
<a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" /> <a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" />
<!-- 引用与代码 --> <!-- 引用与代码 -->
<a-button type="text" size="small" @click="triggerAction('quote')" title="引用"> <a-button type="text" size="small" @click="$emit('action', 'quote')" title="引用">
<template #icon><MessageOutlined /></template> <template #icon><MessageOutlined /></template>
</a-button> </a-button>
<a-button type="text" size="small" @click="triggerAction('inlineCode')" title="行内代码"> <a-button type="text" size="small" @click="$emit('action', 'inlineCode')" title="行内代码">
<template #icon><CodeOutlined /></template> <template #icon><CodeOutlined /></template>
</a-button> </a-button>
<a-button type="text" size="small" @click="triggerAction('link')" title="链接"> <a-button type="text" size="small" @click="$emit('action', 'link')" title="链接">
<template #icon><LinkOutlined /></template> <template #icon><LinkOutlined /></template>
</a-button> </a-button>
<a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" /> <a-divider type="vertical" style="height: 1.2em; background-color: var(--border-color);" />
<!-- 列表 --> <!-- 列表 -->
<a-button type="text" size="small" @click="triggerAction('unorderedList')" title="无序列表"> <a-button type="text" size="small" @click="$emit('action', 'unorderedList')" title="无序列表">
<template #icon><UnorderedListOutlined /></template> <template #icon><UnorderedListOutlined /></template>
</a-button> </a-button>
<a-button type="text" size="small" @click="triggerAction('orderedList')" title="有序列表"> <a-button type="text" size="small" @click="$emit('action', 'orderedList')" title="有序列表">
<template #icon><OrderedListOutlined /></template> <template #icon><OrderedListOutlined /></template>
</a-button> </a-button>
</a-space> </a-space>
@ -68,9 +68,8 @@ import {
OrderedListOutlined, OrderedListOutlined,
LinkOutlined LinkOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { useEditor } from '../composables/useEditor';
const { triggerAction } = useEditor(); defineEmits(['action']);
</script> </script>
<style scoped> <style scoped>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="live-editor"> <div class="live-editor">
<EditorToolbar /> <EditorToolbar @action="handleToolbarAction" />
<codemirror <codemirror
v-model="code" v-model="code"
placeholder="请输入 Markdown 内容..." placeholder="请输入 Markdown 内容..."
@ -16,7 +16,7 @@
</template> </template>
<script setup> <script setup>
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch, shallowRef } from 'vue'
import { Codemirror } from 'vue-codemirror' import { Codemirror } from 'vue-codemirror'
import { markdown } from '@codemirror/lang-markdown' import { markdown } from '@codemirror/lang-markdown'
import { EditorView } from '@codemirror/view' import { EditorView } from '@codemirror/view'
@ -44,7 +44,7 @@ const { applyHeading, wrapSelection, prefixLines, insertLink } = useMarkdownActi
// Markdown // Markdown
const markdownExtension = markdown() const markdownExtension = markdown()
const editorView = ref(null) const editorView = shallowRef(null)
let detachPaste = null let detachPaste = null
let removeActionListener = null let removeActionListener = null
@ -267,6 +267,16 @@ const handleReady = (payload) => {
if (activeTab.value?.filePath !== props.filePath || !editorView.value) return if (activeTab.value?.filePath !== props.filePath || !editorView.value) return
const view = editorView.value const view = editorView.value
executeAction(view, action, payload)
})
}
const handleToolbarAction = (action, payload) => {
if (!editorView.value) return
executeAction(editorView.value, action, payload)
}
const executeAction = (view, action, payload) => {
switch (action) { switch (action) {
case 'heading': applyHeading(view, payload); break; case 'heading': applyHeading(view, payload); break;
case 'bold': wrapSelection(view, '**', '**'); break; case 'bold': wrapSelection(view, '**', '**'); break;
@ -278,9 +288,9 @@ const handleReady = (payload) => {
case 'orderedList': prefixLines(view, (i) => `${i + 1}. `); break; case 'orderedList': prefixLines(view, (i) => `${i + 1}. `); break;
case 'link': insertLink(view); break; case 'link': insertLink(view); break;
} }
})
} }
onUnmounted(() => { onUnmounted(() => {
if (typeof detachPaste === 'function') detachPaste() if (typeof detachPaste === 'function') detachPaste()
if (removeActionListener) removeActionListener() if (removeActionListener) removeActionListener()