1、什么是组合式API
Vue 3.0 中新增了组合式 API 的功能,它是一组附加的、基于函数的 API,可以更加灵活地组织组件代码。通过组合式 API 可以使用函数而不是声明选项的方式来编写 Vue 组件。因此,使用组合式 API 可以将组件代码编写为多个函数,每个函数处理一个特定的功能,不再需要按选项组织代码。
组合式 API 可以更好地和 TypeScript 集成,同时,组合式 API 可以和现有的基于选项的 API 一起使用。需要注意的是,组合式 API 是在选项(data、methods 和 computed)之前进行解析,因此组合式 API 无法访问这些选项中定义的属性。
2、setup()函数的基本用法
setup() 函数是一个新的组件选项,它是组件内部使用组合式 API 的入口。setup() 函数在组件实例创建之前,初始化 Prop 之后调用,而且 setup() 函数是在 beforeCreate 钩子函数之前调用。
setup() 函数可以返回一个对象或函数,对象的属性会合并到组件模板渲染的上下文中。
【实例】创建一个组件,使用 setup() 函数实现一个计数器功能。
<template>
<div>
<h3>{{ blogInfo.name }}</h3>
<h3>{{ blogInfo.url }}</h3>
<p>计数结果:{{ count }}</p>
<button @click="counter">计数器</button>
</div>
</template>
<script>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
export default {
setup() {
// 使用 ref 创建响应式的基本类型
const count = ref(0);
// 使用 reactive 创建响应式的复杂类型
const blogInfo = reactive({
name: '您好,欢迎访问 pan_junbiao的博客',
url: 'https://blog.csdn.net/pan_junbiao'
});
// 挂载时的操作
onMounted(() => {
console.log('组件已挂载');
});
// 卸载时的操作
onUnmounted(() => {
console.log('组件已卸载');
});
// 增加计数的方法
function counter() {
count.value++;
}
// 返回需要在模板中使用的数据和方法
return {
blogInfo,
count,
counter
};
}
};
</script>
执行结果:
上述代码中,setup() 函数返回的是一个对象,在对象有三个属性,其中两个响应式对象,和一个函数。在组件的模板仲可以直接使用这些属性。
注意:
setup() 函数中不能使用 this。但是,当和现有的基于选项的 API 一起使用时,在选项中可以通过 this 访问 setup() 函数返回的实现。
3、setup()函数的参数
setup() 函数可以接收两个可选的参数。第一个参数是响应式的 props 对象,第二个参数是一个上下文(context)对象。
3.1 第一个参数:响应式的 props 对象
第一个参数是响应式的 props 对象,通过该参数可以访问 props 选项中定义的 Prop。
【实例】使用setup()函数中的第一个参数:响应式的 props 对象。
(1)创建 ParentComponent.vue 父组件
<template>
<fieldset>
<legend>父组件</legend>
<h3>使用Prop实现父组件向子组件传递数据</h3>
<!-- 第三步:使用组件,并向子组件传递数据 -->
<ChildComponent :blogName="blogInfo.blogName" :blogUrl="blogInfo.blogUrl" />
</fieldset>
</template>
<script>
import { reactive } from 'vue';
//第一步:引用组件
import ChildComponent from '@/components/ChildComponent.vue'
export default {
//第二步:注册组件
components: {
ChildComponent,
},
setup() {
// 使用 reactive 创建响应式的对象
const blogInfo = reactive({
blogName: '您好,欢迎访问 pan_junbiao的博客',
blogUrl: 'https://blog.csdn.net/pan_junbiao'
});
//返回
return {
blogInfo
}
}
}
</script>
(2)创建 ChildComponent.vue 子组件
<template>
<fieldset>
<legend>子组件</legend>
<p>博客信息:{{ props.blogName }}</p>
<p>博客地址:{{ props.blogUrl }}</p>
</fieldset>
</template>
<script>
export default {
// 使用 props 属性:接收父组件传递过来的数据
props: ['blogName', 'blogUrl'],
//setup()函数的第一个参数是响应式的 props 对象。
setup(props) {
return {
props
};
}
}
</script>
<style scoped>
fieldset {
font-size: 18px;
color: blue;
}
</style>
(3)在 App.vue 根组件中,引入父组件
<template>
<!-- 第三步:使用组件 -->
<ParentComponent />
</template>
<script>
//第一步:引用组件
import ParentComponent from '@/components/ParentComponent.vue'
export default {
//第二步:注册组件
components: {
ParentComponent,
}
}
</script>
执行结果:
3.2 第二个参数:上下文(context)对象
第二个参数是一个上下文(context)对象,该对象是一个 JavaScript 对象,它暴露了 attrs、slots 和 emit 三个属性。其中,attrs 和 slots 是有状态的对象,它们会随着组件的更新而发生变化,但是这两个对象本身并不是响应式的,因此不能对它们进行解构。
【实例】使用setup()函数中的第二个参数:上下文(context)对象。
export default {
//setup()函数的第一个参数:响应式的 props 对象。
//setup()函数的第二个参数:上下文(context)对象
setup(props, context) {
//属性(非响应式对象)
console.log('属性:', context.attrs);
//插槽(非响应式对象)
console.log('插槽:', context.slots);
//发生的事件(方法)
console.log('事件:', context.emit);
}
}
4、使用 <script setup> 语法糖
<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。在 Vue3.2 中只需要在 script 标签上加上 setup 属性,无需 return,template 便可直接使用。相比于普通的 <script> 语法,它具有更多优势:
- 更少的样板内容,更简洁的代码。
- 能够使用纯 TypeScript 声明 props 和自定义事件。
- 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
- 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
【实例】使用 <script setup> 语法糖,重构上述的计数器功能。
<template>
<div>
<h3>{{ blogInfo.name }}</h3>
<h3>{{ blogInfo.url }}</h3>
<p>计数结果:{{ count }}</p>
<button @click="counter">计数器</button>
</div>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
// 使用 ref 创建响应式的基本类型
const count = ref(0);
// 使用 reactive 创建响应式的复杂类型
const blogInfo = reactive({
name: '您好,欢迎访问 pan_junbiao的博客',
url: 'https://blog.csdn.net/pan_junbiao'
});
// 挂载时的操作
onMounted(() => {
console.log('组件已挂载');
});
// 卸载时的操作
onUnmounted(() => {
console.log('组件已卸载');
});
// 增加计数的方法
function counter() {
count.value++;
}
</script>
执行结果: