vue2升级vue3之组合式API与setup

147 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

什么是 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更加简洁呢?

其实实际项目中,业务逻辑远远不止上面的代码这么简单,有许多复杂的逻辑需要处理。

img

上图取自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>
 ​