构建高效待办事项应用
Vue3 Composition API简介
Composition API 是 Vue3 的核心特性之一,它提供了一种更灵活、更强大的代码组织方式。与 Options API 相比,Composition API 允许我们根据逻辑功能而非选项类型来组织代码,特别适合构建复杂应用。
Options API
export default { data() { return { count: 0 } }, methods: { increment() { this.count++ } }, mounted() { console.log('组件已挂载') } }
Composition API
import { ref, onMounted } from 'vue' export default { setup() { const count = ref(0) function increment() { count.value++ } onMounted(() => { console.log('组件已挂载') }) return { count, increment } } }
实战:构建待办事项应用
下面我们将使用 Composition API 构建一个功能完整的待办事项应用,包含以下功能:
- 添加新任务
- 标记任务完成状态
- 编辑任务内容
- 删除任务
- 任务筛选(全部/进行中/已完成)
- 本地存储持久化
我的待办事项
进行中: {{ activeTodosCount }}
已完成: {{ completedTodosCount }}
核心代码解析
import { ref, computed, onMounted, watch } from 'vue' export default { setup() { // 使用ref创建响应式数据 const newTodo = ref('') const todos = ref([]) const filter = ref('all') const editingTodo = ref(null) const editingText = ref('') // 计算属性 const filteredTodos = computed(() => { switch (filter.value) { case 'active': return todos.value.filter(todo => !todo.completed) case 'completed': return todos.value.filter(todo => todo.completed) default: return todos.value } }) const activeTodosCount = computed(() => todos.value.filter(todo => !todo.completed).length ) const completedTodosCount = computed(() => todos.value.filter(todo => todo.completed).length ) // 方法 function addTodo() { if (newTodo.value.trim()) { todos.value.push({ id: Date.now(), text: newTodo.value.trim(), completed: false }) newTodo.value = '' } } function removeTodo(todo) { todos.value = todos.value.filter(t => t !== todo) } function startEditing(todo) { editingTodo.value = todo editingText.value = todo.text } function doneEdit(todo) { if (editingText.value.trim()) { todo.text = editingText.value.trim() } else { removeTodo(todo) } editingTodo.value = null } // 生命周期钩子 onMounted(() => { const savedTodos = localStorage.getItem('todos') if (savedTodos) { todos.value = JSON.parse(savedTodos) } }) // 侦听器 watch(todos, (newTodos) => { localStorage.setItem('todos', JSON.stringify(newTodos)) }, { deep: true }) return { newTodo, todos, filter, editingTodo, editingText, filteredTodos, activeTodosCount, completedTodosCount, addTodo, removeTodo, startEditing, doneEdit } } }
在这个实现中,我们充分利用了Composition API的特性:
- ref – 创建响应式基本类型数据
- computed – 创建基于其他状态的计算属性
- watch – 侦听状态变化并执行副作用
- onMounted – 组件挂载后执行初始化逻辑
- 逻辑复用 – 通过setup函数组织相关逻辑
Composition API的优势
更好的代码组织
将相关逻辑组织在一起,而不是分散在多个选项中
逻辑复用能力
通过组合式函数轻松提取和复用逻辑
更好的类型推断
对TypeScript提供更完善的支持
更小的生产包
优化后的Tree-shaking减少打包体积
最佳实践建议
- 使用
ref
处理基本类型,reactive
处理对象 - 使用
computed
处理派生状态 - 复杂的组件逻辑拆分为多个组合式函数
- 在
watch
中执行副作用操作 - 使用
toRefs
解构响应式对象
总结
通过本教程,我们学习了Vue3 Composition API的核心概念,并构建了一个功能完整的待办事项应用。Composition API提供了一种更灵活、更强大的代码组织方式,特别适合构建复杂应用。
主要收获:
- 掌握了
ref
、computed
、watch
等核心API的使用 - 理解了响应式数据的管理方式
- 学会了如何组织组件逻辑
- 实现了组件状态持久化
- 了解了Composition API相对于Options API的优势
要进一步学习Vue3,推荐探索:
- 组合式函数的提取与复用
- 使用Provide/Inject进行跨组件通信
- Vue3与TypeScript的深度集成
- Vue Router和Pinia状态管理
const { createApp, ref, computed, onMounted, watch } = Vue
// 自定义指令:自动聚焦
const vFocus = {
mounted: (el) => el.focus()
}
createApp({
setup() {
// 响应式数据
const newTodo = ref(”)
const todos = ref([])
const filter = ref(‘all’)
const editingTodo = ref(null)
const editingText = ref(”)
// 计算属性
const filteredTodos = computed(() => {
switch (filter.value) {
case ‘active’:
return todos.value.filter(todo => !todo.completed)
case ‘completed’:
return todos.value.filter(todo => todo.completed)
default:
return todos.value
}
})
const activeTodosCount = computed(() =>
todos.value.filter(todo => !todo.completed).length
)
const completedTodosCount = computed(() =>
todos.value.filter(todo => todo.completed).length
)
// 方法
function addTodo() {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value.trim(),
completed: false
})
newTodo.value = ”
}
}
function removeTodo(todo) {
todos.value = todos.value.filter(t => t !== todo)
}
function startEditing(todo) {
editingTodo.value = todo
editingText.value = todo.text
}
function doneEdit(todo) {
if (editingText.value.trim()) {
todo.text = editingText.value.trim()
} else {
removeTodo(todo)
}
editingTodo.value = null
}
function cancelEdit() {
editingTodo.value = null
}
// 生命周期钩子
onMounted(() => {
const savedTodos = localStorage.getItem(‘todos’)
if (savedTodos) {
todos.value = JSON.parse(savedTodos)
}
})
// 侦听器
watch(todos, (newTodos) => {
localStorage.setItem(‘todos’, JSON.stringify(newTodos))
}, { deep: true })
return {
newTodo,
todos,
filter,
editingTodo,
editingText,
filteredTodos,
activeTodosCount,
completedTodosCount,
addTodo,
removeTodo,
startEditing,
doneEdit,
cancelEdit
}
},
directives: { focus: vFocus }
}).mount(‘#app’)