Skip to content

Commit ab6926c

Browse files
authored
Merge pull request #99 from BUAA-SE-coders007/note-beatify
feat: 美化编辑器
2 parents e614e1a + fa0df6b commit ab6926c

File tree

1 file changed

+86
-59
lines changed

1 file changed

+86
-59
lines changed

src/components/Editor/MdEditor.vue

Lines changed: 86 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
:toolbars="toolbars"
77
:preview="'live'"
88
:language="language"
9-
:style="editorStyle"
109
:dragWidth="dragWidth"
10+
:catalogLayout="'fixed'"
11+
:previewTheme="'github'"
1112
@onSave="handleSave"
1213
@onUploadImg="handleUploadImg"
1314
@onChange="handleChange"
@@ -21,7 +22,7 @@
2122
<script>
2223
import { MdEditor } from 'md-editor-v3';
2324
import 'md-editor-v3/lib/style.css';
24-
import { ref, onMounted, onBeforeUnmount, watch, computed } from 'vue';
25+
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
2526
import { updateNote, getNotes } from '@/api/note';
2627
import { ElMessage } from 'element-plus';
2728
@@ -35,10 +36,6 @@ export default {
3536
type: String,
3637
default: '',
3738
},
38-
height: {
39-
type: Number,
40-
default: 600,
41-
},
4239
autoSave: {
4340
type: Boolean,
4441
default: false,
@@ -59,14 +56,10 @@ export default {
5956
type: String,
6057
default: 'light',
6158
},
62-
fullHeight: {
63-
type: Boolean,
64-
default: true,
65-
},
6659
dragWidth: {
6760
type: String,
6861
default: '50%', // 默认编辑区和预览区等宽
69-
}
62+
},
7063
},
7164
emits: ['update:modelValue', 'save', 'change', 'error', 'dragWidth'],
7265
setup(props, { emit }) {
@@ -77,47 +70,70 @@ export default {
7770
const hasChanges = ref(false); // 标记是否有未保存的更改
7871
let autoSaveTimer = null;
7972
80-
// 计算编辑器样式,设置高度
81-
const editorStyle = computed(() => {
82-
if (props.fullHeight) {
83-
return {
84-
height: 'calc(100vh - 100px)',
85-
};
86-
}
87-
return {
88-
height: `${props.height}px`,
89-
};
90-
});
9173
9274
// 配置工具栏
9375
const toolbars = [
94-
'bold', 'underline', 'italic', 'strikethrough', '-',
95-
'title', 'quote', 'unorderedList', 'orderedList', 'task', '-',
96-
'codeRow', 'code', 'link', 'image', 'table', 'mermaid', '-',
97-
'revoke', 'next', 'save', '=',
98-
'preview', 'htmlPreview', 'catalog', 'fullscreen'
76+
'bold',
77+
'underline',
78+
'italic',
79+
'strikethrough',
80+
'-',
81+
'title',
82+
'quote',
83+
'unorderedList',
84+
'orderedList',
85+
'task',
86+
'-',
87+
'codeRow',
88+
'code',
89+
'link',
90+
'image',
91+
'table',
92+
'mermaid',
93+
'katex',
94+
'-',
95+
'revoke',
96+
'next',
97+
'save',
98+
'=',
99+
'preview',
100+
'previewOnly',
101+
'catalog',
102+
'pageFullscreen',
103+
'fullscreen',
99104
];
100105
106+
const footers = ['markdownTotal', '=', 'scrollSwitch']
107+
101108
// 设置语言
102109
const language = 'zh-CN';
103110
104111
// 监听值变化和noteId变化
105-
watch(() => props.modelValue, (newValue) => {
106-
if (newValue !== content.value) {
107-
content.value = newValue;
112+
watch(
113+
() => props.modelValue,
114+
(newValue) => {
115+
if (newValue !== content.value) {
116+
content.value = newValue;
117+
}
108118
}
109-
});
110-
119+
);
120+
111121
// 监听noteId变化,以便加载不同的笔记
112-
watch(() => props.noteId, async (newNoteId, oldNoteId) => {
113-
if (newNoteId && newNoteId !== oldNoteId) {
114-
await fetchNoteContent(newNoteId);
122+
watch(
123+
() => props.noteId,
124+
async (newNoteId, oldNoteId) => {
125+
if (newNoteId && newNoteId !== oldNoteId) {
126+
await fetchNoteContent(newNoteId);
127+
}
115128
}
116-
});
129+
);
117130
118-
watch(() => content.value, (newValue) => {
119-
emit('update:modelValue', newValue);
120-
});
131+
watch(
132+
() => content.value,
133+
(newValue) => {
134+
emit('update:modelValue', newValue);
135+
}
136+
);
121137
122138
const handleChange = (value) => {
123139
hasChanges.value = true; // 当内容改变时,标记有未保存的更改
@@ -146,34 +162,39 @@ export default {
146162
try {
147163
await updateNote(props.noteId, { content: currentContent });
148164
if (showNotification) {
149-
ElMessage.success("笔记已保存"); // 手动保存时显示
165+
ElMessage.success('笔记已保存'); // 手动保存时显示
150166
}
151167
hasChanges.value = false; // 保存成功后重置标记
152168
} catch (e) {
153169
ElMessage.error(`保存失败: ${e.message}`); // 统一错误信息
154-
console.error("保存失败", e);
170+
console.error('保存失败', e);
155171
} finally {
156172
updating.value = false;
157173
}
158174
};
159175
160176
const handleUploadImg = async (files, callback) => {
161177
try {
162-
ElMessage.info("图片上传功能尚未实现");
178+
ElMessage.info('图片上传功能尚未实现');
163179
// 这里后续可以接入专门的图片上传 API
164180
// 目前简单返回空数组,避免报错
165181
callback([]);
166182
} catch (error) {
167-
ElMessage.error("图片上传失败");
168-
console.error("图片上传失败", error);
183+
ElMessage.error('图片上传失败');
184+
console.error('图片上传失败', error);
169185
}
170186
};
171187
172188
// 获取笔记内容
173189
const fetchNoteContent = async (noteId) => {
174190
try {
175191
const response = await getNotes({ id: noteId });
176-
if (response && response.status === 200 && response.data.notes && response.data.notes.length > 0) {
192+
if (
193+
response &&
194+
response.status === 200 &&
195+
response.data.notes &&
196+
response.data.notes.length > 0
197+
) {
177198
content.value = response.data.notes[0].content || '';
178199
emit('update:modelValue', content.value);
179200
return content.value;
@@ -207,7 +228,8 @@ export default {
207228
}
208229
};
209230
210-
const handleBeforeUnload = (event) => { // Renamed back to 'event' as it will be used
231+
const handleBeforeUnload = (event) => {
232+
// Renamed back to 'event' as it will be used
211233
if (props.autoSave && hasChanges.value && props.noteId) {
212234
// 尝试在页面卸载前保存笔记 (如果当前没有正在进行的保存操作)
213235
// 注意: 异步操作在 beforeunload 事件中不保证完成
@@ -227,7 +249,7 @@ export default {
227249
if (props.noteId) {
228250
await fetchNoteContent(props.noteId);
229251
}
230-
252+
231253
// 自动聚焦
232254
if (props.autoFocus && mdEditorRef.value) {
233255
mdEditorRef.value.focus();
@@ -240,16 +262,24 @@ export default {
240262
clearAutoSave(); // 组件卸载前清除定时器
241263
window.removeEventListener('beforeunload', handleBeforeUnload);
242264
// Vue 组件卸载时的保存逻辑 (例如SPA内部导航)
243-
if (props.autoSave && hasChanges.value && props.noteId && !updating.value) {
265+
if (
266+
props.autoSave &&
267+
hasChanges.value &&
268+
props.noteId &&
269+
!updating.value
270+
) {
244271
// 退出前自动保存,不显示通知
245-
saveNote(content.value, false);
272+
saveNote(content.value, false);
246273
}
247274
});
248275
249276
// 监听 autoSave 和 noteId 的变化以重新启动定时器
250-
watch(() => [props.autoSave, props.noteId, props.autoSaveInterval], () => {
251-
startAutoSave();
252-
});
277+
watch(
278+
() => [props.autoSave, props.noteId, props.autoSaveInterval],
279+
() => {
280+
startAutoSave();
281+
}
282+
);
253283
254284
const insertContent = (text) => {
255285
if (mdEditorRef.value) {
@@ -276,19 +306,19 @@ export default {
276306
return {
277307
content,
278308
toolbars,
309+
footers,
279310
language,
280311
preview,
281312
mdEditorRef,
282313
updating,
283-
editorStyle,
284314
handleChange,
285315
handleError,
286316
handleSave,
287317
handleUploadImg,
288318
handleDragWidth,
289319
insertContent,
290320
getValue,
291-
fetchNoteContent // 导出这个方法供外部使用
321+
fetchNoteContent, // 导出这个方法供外部使用
292322
};
293323
},
294324
};
@@ -304,10 +334,10 @@ export default {
304334
}
305335
306336
/* 设置编辑区和预览区可以调整大小 */
307-
:deep(.md-editor-content) {
337+
/* :deep(.md-editor-content) {
308338
display: flex;
309339
height: 100%;
310-
}
340+
} */
311341
312342
:deep(.md-editor-content .md-editor-input-wrapper),
313343
:deep(.md-editor-content .md-editor-preview-wrapper) {
@@ -324,7 +354,6 @@ export default {
324354
background-color: var(--md-border-hover-color);
325355
}
326356
327-
/* 设置编辑器填满容器 */
328357
:deep(.md-editor) {
329358
position: relative;
330359
height: 100%;
@@ -334,7 +363,6 @@ export default {
334363
335364
/* 工具栏样式 */
336365
:deep(.md-editor-toolbar) {
337-
height: 46px;
338366
z-index: 10;
339367
background-color: var(--md-bk-color, #fff);
340368
}
@@ -357,5 +385,4 @@ export default {
357385
:deep(.md-editor-preview) ul li ul li {
358386
list-style-type: circle !important;
359387
}
360-
361388
</style>

0 commit comments

Comments
 (0)