彻底掌握md-editor-v3任务列表:从勾选到自定义事件全攻略
你是否遇到这些任务列表痛点?
- 勾选状态变更无法触发业务逻辑
- 无法获取勾选操作的行号与内容
- 预览模式下勾选状态同步困难
- 自定义样式与默认行为冲突
本文将通过10个实战步骤+7段核心代码,教你全面掌控任务列表的勾选事件,实现状态监听、数据同步、业务联动的全流程自定义。
任务列表事件机制解析
核心事件原理
md-editor-v3通过事件总线(Event Bus)实现任务状态变更通知,核心事件为TASK_STATE_CHANGED,定义于static/event-name.ts:
export const TASK_STATE_CHANGED = 'taskStateChanged';
事件触发流程:
事件参数详解
| 参数名 | 类型 | 描述 | 示例 |
|---|---|---|---|
| lineNumber | number | 任务所在行号(从1开始) | 3 |
| targetValue | string | 修改后的行内容 | "- [x] 完成文档编写" |
基础实现:监听任务状态变更
1. 设置编辑器唯一标识
<template>
<MdEditor
v-model="content"
id="my-editor" <!-- 必须设置唯一ID用于事件总线 -->
/>
</template>
2. 引入事件总线与事件常量
import bus from 'md-editor-v3/dist/utils/event-bus';
import { TASK_STATE_CHANGED } from 'md-editor-v3/dist/static/event-name';
3. 注册事件监听器
onMounted(() => {
// 注册事件监听
bus.on('my-editor', {
name: TASK_STATE_CHANGED,
callback: handleTaskChange
});
});
// 事件处理函数
const handleTaskChange = (lineNumber, targetValue) => {
console.log(`第${lineNumber}行任务状态变更为:`, targetValue);
// 业务逻辑处理...
};
4. 组件卸载时清理事件
onBeforeUnmount(() => {
// 清除指定编辑器的所有事件监听
bus.clear('my-editor');
});
高级实战:实现复杂业务场景
场景1:任务状态持久化
const handleTaskChange = async (lineNumber, targetValue) => {
// 解析任务内容与状态
const isChecked = targetValue.includes('[x]');
const taskContent = targetValue.replace(/- \[x\] /, '').replace(/- \[\s\] /, '');
// 调用API保存状态
await api.saveTaskStatus({
line: lineNumber,
content: taskContent,
completed: isChecked,
documentId: 'doc-123'
});
};
场景2:跨组件任务状态同步
// 父组件中
const taskStates = ref<Record<number, boolean>>({});
const handleTaskChange = (lineNumber, targetValue) => {
const isChecked = targetValue.includes('[x]');
taskStates.value[lineNumber] = isChecked;
// 通知其他组件
emits('task-updated', { lineNumber, isChecked });
};
场景3:预览模式下的状态修改
预览模式(previewOnly)下需要特殊处理:
<template>
<MdEditor
v-model="content"
:previewOnly="true"
@change="handleContentChange" <!-- 预览模式下通过change事件同步 -->
/>
</template>
<script setup>
const handleContentChange = (newContent) => {
// 解析所有任务状态
const lines = newContent.split('\n');
const tasks = lines
.map((line, index) => ({
line: index + 1,
content: line,
completed: line.includes('- [x]')
}))
.filter(item => item.content.startsWith('- [') && item.content.includes('] '));
console.log('所有任务状态:', tasks);
};
</script>
任务列表渲染与样式自定义
默认任务列表结构
<!-- 渲染后的HTML结构 -->
<div class="task-list-item enabled" data-line="2">
<input class="task-list-item-checkbox" type="checkbox" checked>
<label class="task-list-item-label">完成文档编写</label>
</div>
自定义勾选框样式
/* 自定义勾选框样式 */
.md-editor-v3 .task-list-item-checkbox {
width: 18px;
height: 18px;
margin-right: 8px;
accent-color: #42b983; /* Vue绿色主题 */
border-radius: 4px;
}
/* 暗黑模式适配 */
.md-editor-v3-dark .task-list-item-checkbox {
accent-color: #359e75;
}
常见问题解决方案
Q1: 事件不触发怎么办?
Q2: 如何获取任务列表的完整数据?
const parseTasks = (content) => {
return content.split('\n')
.map((line, index) => ({
lineNumber: index + 1,
text: line.replace(/- \[(x| )\] /, ''),
completed: line.includes('- [x]'),
original: line
}))
.filter(item => /^- \[(x| )\] /.test(item.original));
};
// 使用示例
const tasks = parseTasks(content);
console.log('解析后的任务列表:', tasks);
Q3: 如何禁止特定任务的勾选?
const handleTaskChange = (lineNumber, targetValue) => {
// 禁止第2行任务修改
if (lineNumber === 2) {
// 恢复原始状态
const lines = content.value.split('\n');
lines[lineNumber - 1] = lines[lineNumber - 1].includes('[x]')
? '- [x] 禁止修改的任务'
: '- [ ] 禁止修改的任务';
content.value = lines.join('\n');
alert('该任务禁止修改状态');
}
};
性能优化与最佳实践
事件防抖处理
import { debounce } from 'lodash-es';
// 防抖处理,避免快速勾选时频繁触发
const debouncedHandleTaskChange = debounce((lineNumber, targetValue) => {
// 实际业务处理
}, 300);
// 注册防抖后的处理函数
bus.on('my-editor', {
name: TASK_STATE_CHANGED,
callback: debouncedHandleTaskChange
});
批量任务操作
// 全选/取消全选功能
const toggleAllTasks = (checked) => {
const lines = content.value.split('\n');
const newLines = lines.map(line => {
if (/^- \[(x| )\] /.test(line)) {
return checked ? line.replace('- [ ] ', '- [x] ') : line.replace('- [x] ', '- [ ] ');
}
return line;
});
content.value = newLines.join('\n');
};
任务状态可视化
<template>
<div class="task-stats">
<div class="progress-bar">
<div
class="progress"
:style="{ width: `${(completedCount / totalCount) * 100}%` }"
></div>
</div>
<p>{{ completedCount }}/{{ totalCount }} 任务已完成</p>
</div>
</template>
<script setup>
const completedCount = computed(() => {
return (content.value.match(/- \[x\]/g) || []).length;
});
const totalCount = computed(() => {
return (content.value.match(/- \[(x| )\]/g) || []).length;
});
</script>
完整示例代码
<template>
<div class="task-editor-demo">
<MdEditor
v-model="content"
id="task-editor"
:toolbars="['bold', 'italic', 'task']"
:preview="true"
height="500px"
/>
<div class="task-log">
<h3>操作日志</h3>
<ul>
<li v-for="log in logs" :key="log.id">
{{ new Date(log.time).toLocaleTimeString() }} - {{ log.message }}
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import MdEditor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import bus from 'md-editor-v3/dist/utils/event-bus';
import { TASK_STATE_CHANGED } from 'md-editor-v3/dist/static/event-name';
const content = ref(`# 任务列表示例
- [ ] 学习事件总线机制
- [ ] 实现任务状态监听
- [ ] 完成自定义业务逻辑
- [x] 初始化编辑器
`);
const logs = ref<Array<{ id: number; time: number; message: string }>>([]);
let logId = 1;
// 解析任务状态
const taskStats = computed(() => {
const lines = content.value.split('\n');
const tasks = lines.filter(line => /^- \[(x| )\] /.test(line));
const completed = tasks.filter(line => line.includes('- [x]')).length;
return {
total: tasks.length,
completed,
progress: tasks.length ? Math.round((completed / tasks.length) * 100) : 0
};
});
// 任务变更处理函数
const handleTaskChange = (lineNumber: number, targetValue: string) => {
const isChecked = targetValue.includes('[x]');
const taskText = targetValue.replace(/- \[x\] /, '').replace(/- \[\s\] /, '');
// 添加操作日志
logs.value.unshift({
id: logId++,
time: Date.now(),
message: `任务 "${taskText}" 已${isChecked ? '完成' : '取消'} (行: ${lineNumber})`
});
// 仅保留最近10条日志
if (logs.value.length > 10) {
logs.value.pop();
}
// 业务逻辑:当所有任务完成时提示
if (isChecked && taskStats.value.completed === taskStats.value.total) {
alert('恭喜!所有任务已完成!');
}
};
onMounted(() => {
// 注册事件监听
bus.on('task-editor', {
name: TASK_STATE_CHANGED,
callback: handleTaskChange
});
});
onBeforeUnmount(() => {
// 清理事件监听
bus.clear('task-editor');
});
</script>
<style scoped>
.task-editor-demo {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.task-log {
margin-top: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
}
.task-log h3 {
margin-top: 0;
color: #333;
}
.task-log ul {
list-style: none;
padding: 0;
margin: 0;
}
.task-log li {
padding: 8px 0;
border-bottom: 1px solid #eee;
font-size: 14px;
color: #666;
}
.task-log li:last-child {
border-bottom: none;
}
</style>
总结与进阶展望
通过本文学习,你已掌握: ✅ 任务列表事件监听的完整流程 ✅ 3种核心业务场景的实现方案 ✅ 5个常见问题的解决方案 ✅ 性能优化与最佳实践
进阶方向
- 实现任务拖拽排序与状态联动
- 结合Vuex/Pinia实现全局任务状态管理
- 开发任务完成动画与交互反馈
- 集成第三方任务管理API(如Trello)
希望本文能帮助你彻底掌握md-editor-v3的任务列表功能。如有任何问题,欢迎在评论区留言讨论。记得收藏本文,以便后续开发查阅!
下一篇预告:《md-editor-v3高级插件开发指南》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



