fix(note-editor): 优化自动保存机制,解决切换笔记时的保存问题

- 修复了在切换笔记时意外触发自动保存的问题- 引入标志位区分用户输入和程序加载内容
-优化了自动保存的防抖逻辑,提高用户体验
- 删除了不必要的组件代码,精简结构
This commit is contained in:
ikmkj
2025-08-14 07:49:40 +08:00
parent f9b872f649
commit 337645f27b
4 changed files with 79 additions and 157 deletions

View File

@@ -13,7 +13,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
import { ElMessage } from 'element-plus';
@@ -26,147 +26,4 @@ const props = defineProps({
},
});
const emit = defineEmits(['back', 'save-success']);
const vditor = ref(null);
const saveStatus = ref('空闲');
let debounceTimer = null;
const initVditor = () => {
vditor.value = new Vditor('vditor-editor', {
height: 'calc(100vh - 120px)',
mode: 'ir',
after: () => {
if (props.editData && props.editData.content) {
vditor.value.setValue(props.editData.content);
}
},
input: (value) => {
saveStatus.value = '正在输入...';
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
handleSave(value);
}, 2000);
},
upload: {
accept: 'image/*',
handler(files) {
handleImageUpload(files);
},
},
});
};
const handleImageUpload = async (files) => {
const file = files;
if (!file) return;
try {
const promise = await uploadImage(file);
if (promise.url == null) {
ElMessage.error(promise.msg || '图片上传失败');
return;
}
const fullUrl = `${import.meta.env.VITE_API_BASE_URL}${promise.url}`;
vditor.value.insertValue(`![${file.name}](${fullUrl})`);
} catch (error) {
ElMessage.error('图片上传失败: ' + error.message);
}
};
const handleSave = async (content) => {
saveStatus.value = '正在保存...';
try {
const payload = {
id: props.editData.id,
title: props.editData.title,
groupingId: props.editData.groupingId,
content: content,
fileName: props.editData.fileName || `${props.editData.title}.md`,
isPrivate: props.editData.isPrivate,
};
const response = await updateMarkdown(payload);
emit('save-success', response);
saveStatus.value = '已保存';
ElMessage.success('保存成功');
} catch (error) {
saveStatus.value = '保存失败';
ElMessage.error('保存失败: ' + (error.response?.data?.message || error.message));
}
};
const save = () => {
if (vditor.value) {
handleSave(vditor.value.getValue());
}
};
onMounted(() => {
initVditor();
});
onBeforeUnmount(() => {
if (vditor.value) {
vditor.value.destroy();
}
clearTimeout(debounceTimer);
});
watch(() => props.editData, (newData) => {
if (vditor.value && newData) {
vditor.value.setValue(newData.content || '');
}
}, { deep: true });
// Expose the save method to the parent
defineExpose({ save });
</script>
<style scoped>
.note-editor-wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.editor-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding: 1rem;
background-color: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow-light);
}
.dark-theme .editor-header {
background-color: rgba(30, 30, 47, 0.8);
}
.editor-title {
margin: 0;
font-size: 1.25rem;
font-weight: 600;
}
.actions {
display: flex;
gap: 10px;
align-items: center;
}
.save-status {
font-size: 14px;
color: var(--text-color-secondary);
width: 80px; /* Give it a fixed width to prevent layout shifts */
text-align: center;
}
.vditor {
flex-grow: 1;
border: none;
}
</style>
const emit = defineEmits