本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是 Composition API ?
Composition API 也就是组合式API,它是一套能够灵活组合组件逻辑,且基于函数式的和渐进式的 APIs。
通俗点来说就是 Vue3 提供了一种新的方式(组合函数式)来组织和编写组件的逻辑代码。
与之相对的是vue2的Option API即选项式API。
- Composition API 将来会慢慢替代 Vue2 的 Options API,虽然 Vue3 仍然兼容 Vue2 的 Options API,但站在代码的可读性、维护性和一致性的角度来看,你最好不要两者都在同一个组件中使用。
- Vue2 中的 Options API 能做的事,Composition API 都能做,反之则不行。在 Options API 里面无法直接复用组件的逻辑,只能通过 Mixin(混入),但它不是很好的选择,随着组件的复杂度增长,它无法清晰的展示数据状态来源,稍不注意还会造成命名冲突等问题,会给项目带来副作用。
- Composition API 更面向未来。
对于相同业务逻辑的代码,二者写法不同:
Composition API
<template>
<div>
<button @click="increment">Button tapped {{state.times}} times</button>
</div>
</template>
<script>
import { createComponent, reactive } from 'vue'
export default createComponent({
setup() {
let state = reactive({
times: 0
})
const increment = () => {
state.times++
}
return {
state,
increment
}
}
})
</script>
Options API
<template>
<div>
<button @click="increment">Button tapped {{times}} times</button>
</div>
</template>
<script>
export default {
data() {
return {
times: 0
}
},
methods: {
increment() {
this.times++
}
}
}
</script>
可以看到它们之间区别挺大的,并且好像Options API更加简洁呢?
其实实际项目中,业务逻辑远远不止上面的代码这么简单,有许多复杂的逻辑需要处理。
上图取自vue3官网,相同的颜色表示同一个逻辑业务相关的代码,可以明显看到,使用组合式API无论对于代码书写还是后期维护和拓展都更加有利。
setup函数和setup语法糖
setup函数
import { createComponent, reactive } from 'vue'
export default createComponent({
setup() {
let state = reactive({
times: 0
})
const increment = () => {
state.times++
}
return {
state,
increment
}
}
})
这里使用了setup函数,里面包含所有的业务逻辑的代码,但是还是存在一些问题,比如引入的组件、定义的变量和方法等都需要在setup中一一return出去。下面的setup语法糖很好的解决了这个问题。
setup语法糖
vue3.2提供一种更加便捷的写法,即setup语法糖。
<template>
<div>
<button @click="increment">Button tapped {{state.times}} times</button>
</div>
</template>
<script setup>
let state = reactive({
times: 0
})
const increment = () => {
state.times++
}
</script>
setup语法糖中的变量,方法等在模板中可以直接使用。但是我们无法直接获取到props和emits等通过参数传递的信息了,所以需要使用vue3.2提供的api来解决。
其他API
defineProps
用于获取父组件传递的props。
<template>
<div>
<h2>{{message}}</h2>
</div>
</template>
<script lang="ts" setup>
import {defineProps} from 'vue'
defineProps({
message:{
type:String,
default:'hahha'
}
})
</script>
defineEmits
用于调试父组件调用子组件时定义的方法。
<template>
<div>
<button @click='sendEmit'>给父组件发送事件</button>
</div>
</template>
<script lang="ts" setup>
import {defineEmits} from 'vue'
//使用defineEmits创建名称,接受一个数组
const emit = defineEmits(['sendEmit'])
//调用事件参数
const sendEmit = () =>{
emit('sendEmit','传递的数据')
}
</script>
defineExpose
使用
可以通过 defineExpose 编译器宏来显式指定在
父组件可以通过在组件中设置ref属性,然后在script中声明对应变量,来直接获取子组件实例(并不推荐)。
子组件:ChildComponent.vue
<template>
<div>
<p>{{ name }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const name = ref("ChildComponent");
//暴露
defineExpose({
name,
});
</script>
<style scoped></style>
父组件:
<template>
<ChildComponentVue ref="child"></ChildComponentVue>
</template>
<script setup lang="ts">
import ChildComponentVue from "./ChildComponent.vue";
import { onMounted, ref } from "vue";
let child = ref(null);
//需要在onMounted中获取 因为是获取的DOM实例
onMounted(() => {
console.log(child.value);
});
</script>
<style scoped></style>