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"
2122<script >
2223import { MdEditor } from ' md-editor-v3' ;
2324import ' md-editor-v3/lib/style.css' ;
24- import { ref , onMounted , onBeforeUnmount , watch , computed } from ' vue' ;
25+ import { ref , onMounted , onBeforeUnmount , watch } from ' vue' ;
2526import { updateNote , getNotes } from ' @/api/note' ;
2627import { 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