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>
执行结果: