setup 语法标签,是目前 Vue3 最推荐的写法。
不过这种写法并非一开始就是这样的,而是一步一步演进而来的。
Vue2经典写法
Vue2 时期采用的是 Options API 语法,这是一种经典写法。
TaskManager.vue
export default {
name: 'TaskManager',
props: {
initialTasks: {
type: Array,
required: true,
default: () => []
}
},
data() {
return {
tasks: [...this.initialTasks],
newTaskTitle: '' // 新任务标题
}
},
methods: {
// 新增任务
addTask() {
if (this.newTaskTitle.trim() === '') {
return
}
// 添加新任务
this.tasks.push({
id: Date.now(),
title: this.newTaskTitle,
completed: false
})
this.newTaskTitle = '' // 清空输入框
},
// 标记任务已完成
completeTask(id) {
const task = this.tasks.find((task) => task.id === id)
if (task) {
task.completed = true
this.$emit('task-completed', task)
}
},
// 标记任务未完成
uncompleteTask(id) {
const task = this.tasks.find((task) => task.id === id)
if (task) {
task.completed = false
this.$emit('task-uncompleted', task)
}
}
}
}
Vue3初期写法
Vue3 时期,官方提出了 Composition API 风格,**这种风格能够对组件的共有模块进行一个更好的组合复用**。
import { ref, toRefs } from 'vue'
export default {
name: 'TaskManager',
props: {
initialTasks: {
type: Array,
required: true,
default: () => []
}
},
emits: ['task-completed', 'task-uncompleted'],
setup(props, { emit }) {
// setup是一个生命周期方法
// 在该方法中书写数据以及函数
const { initialTasks } = toRefs(props)
const tasks = ref([...initialTasks.value]) // 任务列表
const newTaskTitle = ref('') // 存储新任务的标题
// 添加任务
const addTask = () => {
if (newTaskTitle.value.trim() === '') {
return
}
tasks.value.push({
id: Date.now(),
title: newTaskTitle.value,
completed: false
})
newTaskTitle.value = ''
}
// 完成任务
const completeTask = (taskId) => {
const task = tasks.value.find((task) => task.id === taskId)
if (task) {
task.completed = true
// 触发自定义事件
emit('task-completed', task)
}
}
// 取消完成任务
const uncompleteTask = (taskId) => {
const task = tasks.value.find((task) => task.id === taskId)
if (task) {
task.completed = false
// 触发自定义事件
emit('task-uncompleted', task)
}
}
// 最后需要返回一个对象
// 该对象里面就包含了需要在模板中使用的数据以及方法
return {
tasks,
newTaskTitle,
addTask,
completeTask,
uncompleteTask
}
}
}
可以看出,早期的 Vue3 的 CompositionAPI 写法,实际上有 OptionsAPI 写法的影子,和 Vue2 的语法有一定的相似性,同样都是导出一个对象,最重要的特点是对象中多了一个 setup 函数。
这是一个新的生命周期钩子方法,在该方法中,我们可以定义对应的数据和方法,并且在最后返回出去,在模板中可以使用所返回的数据和方法。
defineComponent写法
defineComponent 是 Vue 3 中引入的一个辅助函数,主要用于定义 Vue 组件,特别是在使用 TypeScript 时提供更好的类型推断和校验。
通过使用 defineComponent,我们可以:
- 自动推断类型:减少显式类型注解,使代码更简洁。
- 减少冗余:不需要手动定义 Props 接口和响应式数据的类型。
- 提高可读性:使代码更易读、更易维护。
import { defineComponent, toRefs, ref } from 'vue'
export default defineComponent({
name: 'TaskManager',
props: {
initialTasks: {
type: Array,
required: true,
default: () => []
}
},
emits: ['task-completed', 'task-uncompleted'],
setup(props, { emit }) {
// setup是一个生命周期方法
// 在该方法中书写数据以及函数
const { initialTasks } = toRefs(props)
const tasks = ref([...initialTasks.value]) // 任务列表
const newTaskTitle = ref('') // 存储新任务的标题
// 添加任务
const addTask = () => {
if (newTaskTitle.value.trim() === '') {
return
}
tasks.value.push({
id: Date.now(),
title: newTaskTitle.value,
completed: false
})
newTaskTitle.value = ''
}
// 完成任务
const completeTask = (taskId) => {
const task = tasks.value.find((task) => task.id === taskId)
if (task) {
task.completed = true
// 触发自定义事件
emit('task-completed', task)
}
}
// 取消完成任务
const uncompleteTask = (taskId) => {
const task = tasks.value.find((task) => task.id === taskId)
if (task) {
task.completed = false
// 触发自定义事件
emit('task-uncompleted', task)
}
}
// 最后需要返回一个对象
// 该对象里面就包含了需要在模板中使用的数据以及方法
return {
tasks,
newTaskTitle,
addTask,
completeTask,
uncompleteTask
}
}
})
可以看出,defineComponent 仅仅只是一个辅助方法,和 TS 配合得更好。但是并没有从本质上改变初期 Composition API 的写法。
setup标签写法
从 Vue3.2 版本开始正式引入了 setup 语法糖,它简化了使用 Composition API 时的书写方式,使得组件定义更加简洁和直观。
其优化的点主要如下:
- 简化书写:在传统的 setup 函数中,我们需要返回一个对象,其中包含需要在模板中使用的变量和方法。在