【Vue3基础】组合式API

组合式API

1.前言

在Vue3中,有一项对于开发者来说非常有意义的更新 — 组合式API。

在开始介绍之前,需要注意两点:

  • 选项式API和组合式API是两种不同的风格,但它们不是互斥而是并存的!
  • 在需要大量逻辑组合的场景,往往使用组合式API实现

2.组合式API与选项式API

首先是选项式API,基于这种风格开发的Vue应用如左图所示:

  • 各个选项都有固定的书写位置,如:data — 响应式数据、method — 写方法函数…对于一个功能模块,其相关逻辑的代码是分散的。
  • 优点在于:代码结构清晰
  • 缺点在于:代码组织性差,相似的逻辑代码不方便复用,逻辑复杂时,代码庞大,同一功能模块的上下文代码难以关联

其次是组合式API,基于这种风格开发的Vue应用如右图所示:

  • 特定功能模块的相关代码都可以写在一块儿,同一功能的代码集中。
  • 优点在于:
    • 可以快速定位到某个功能模块的相关代码
    • 当逻辑复杂、代码量较大时,可以进行逻辑拆分、功能封装
      在这里插入图片描述
      当逻辑较为复杂时,我们可以进行功能的抽象和拆分,如下图:
      在这里插入图片描述
2.1 案例

光看图只能做到简单了解,下面我们通过一个具体的实例来体会一下两种开发风格的区别:
在这里插入图片描述

这里有两个独立的功能:

  1. 点击按钮控制div的显示与隐藏
  2. 点击按钮控制div内字体颜色的变化
2.3 利用选项式API实现
<template>
  <div>
    <!-- 功能一模板 -->
    <button @click="show">显示</button>
    <button @click="hide">隐藏</button>
    <div v-if="showDiv">一个被控制显隐的div</div>
  </div>
  <div>
    <!-- 功能二模板 -->
    <button @click="changeRed">红色</button>
    <button @click="changeYellow">蓝色</button>
    <div :style="`color:${fontColor}`">一个被控制字体颜色的的div</div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      showDiv: true, // 功能一数据
      fontColor: '' // 功能二数据
    }
  },
  methods: {
    // 功能一方法
    show() {
      this.showDiv = true
    },
    hide() {
      this.showDiv = false
    },
    // 功能二方法
    changeRed() {
      this.fontColor = 'red'
    },
    changeYellow() {
      this.fontColor = 'blue'
    }
  }
}
</script>
2.4 利用组合式API实现
<template>
  <div>
    <!-- 功能一模板 -->
    <button @click="show">显示</button>
    <button @click="hide">隐藏</button>
    <div v-if="showDivFlag">一个被控制显隐的div</div>
  </div>
  <div>
    <!-- 功能二模板 -->
    <button @click="changeRed">红色</button>
    <button @click="changeBlue">蓝色</button>
    <div :style="`color:${fontColor}`">一个被控制字体颜色的的div</div>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'App',
  setup() {
    // 功能一
    const showDivFlag = ref(true)
    function show() {
      showDivFlag.value = true
    }
    function hide() {
      showDivFlag.value = false
    }
    // 功能二

    const fontColor = ref('')
    function changeRed() {
      fontColor.value = 'red'
    }
    function changeBlue() {
      fontColor.value = 'blue'
    }
    return { showDivFlag, show, hide, fontColor, changeRed, changeBlue }
  }
}
</script>

接下来我们对上面的代码进行一下优化:

<script>
import { ref } from 'vue'
function useShow() {
  const showDivFlag = ref(true)
  function show() {
    showDivFlag.value = true
  }
  function hide() {
    showDivFlag.value = false
  }
  return { showDivFlag, show, hide }
}

function useColor() {
  const fontColor = ref('')
  function changeRed() {
    fontColor.value = 'red'
  }
  function changeBlue() {
    fontColor.value = 'blue'
  }
  return { fontColor, changeRed, changeBlue }
}
export default {
  name: 'App',
  setup() {
    // 功能一
    const { showDivFlag, show, hide } = useShow()
    // 功能二
    const { fontColor, changeRed, changeBlue } = useColor()
    return { showDivFlag, show, hide, fontColor, changeRed, changeBlue }
  }
}
</script>

通过定义功能函数,把俩个功能相关的代码各自抽离到一个独立的小函数中,然后通过在 setup 函数中再把俩个小功能函数组合起来,这样一来,我们既可以把 setup 函数变得更为简单清晰,又可以方便维护快速定位功能位置。

当然,这里只是一个小示例而已,在真实的开发过程中,对于多个不同且彼此独立的功能,往往会将其抽象为几个组件,然后分别在对应的组件中编写其内部逻辑代码,最后在父页面中,引入它们的数据、方法,来实现整体需求。

不过,这里并没有涉及到组合式API中的细节,仅仅是进行一个整体的体会。

下面的部分会对组合式API的基础进行简要的介绍。

3.组合式API基础

3.1 setup函数
  1. setup 函数是一个新的组件选项,作为组件中组合式API的起点(入口)
  2. setup 中不能使用thisthis指向undefined
  3. setup函数只会在组件初始化的时候执行一次
  4. setup函数在beforeCreate生命周期钩子执行之前执行

不过现在使用更多的应该是<script setup>语法糖,即下面这种形式:

<script setup>
// 变量
const msg = 'Hello!'
// 函数
function log() {
  console.log(msg)
}
    
//...
</script>

里面的代码会被编译成组件setup()函数的内容。这意味着与普通的<script>只在组件被首次引入的时候执行一次不同,<script setup>中的代码会在每次组件实例被创建的时候执行。

当使用<script setup>的时候,任何在<script setup>声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用!

3.2 ref和reactive函数

它们均用于将普通数据转换为响应式数据。

具体内容和区别等可以看这篇文章:【Vue3基础】ref 和 reactive

3.3 toRef函数

toRef方法用于转换响应式对象中的某一个属性单独的响应式数据,并且,这两者的数据是关联的!

<script setup>
import { reactive, toRef } from 'vue'
const obj = reactive({
    name: 'xiaoming',
    info: {
        age: '10',
        sex: 'male',
    },
})

// 如果需要使用info数据,不能直接解构!例如:const { name } = obj
// 因为直接解构出来的数据不再具有响应式的特性,会变成一个普通数据!
// 隐藏这里就需要用toRef函数
const name = toRef(obj, 'name')
const info = toRef(obj, 'info')

// 更新该数据,原本的响应式对象中的对应属性也会变化
const update = () => {
    name.value = 'xiaowang';
    info.value.age = '14';
}

return { name, updateName };
</script>
3.4 toRefs函数

上面说到过,对于响应式对象,如果将其解构或展开,会让数据丢失响应式的能力!

而在某些场景中,解构或展开该对象又是不可避免的,因此,为了解决这个问题,引入了toRefs函数,使用该函数可以保证该对象展开的每个属性都是响应式的。

<script setup>
import { reactive, toRefs } from 'vue'
const obj = reactive({
    name: 'xiaoming',
    info: {
        age: '10',
        sex: 'male',
    },
})

// 这里需要将obj对象的各属性返回,因此使用扩展运算符是最为简单方便的
// 但扩展运算符会导致展开的数据失去响应式特性,所以需要配置toRefs函数使用
return { ...toRefs(obj) };
</script>
3.5 生命周期

在这里插入图片描述

需要注意的是,在组合式API中,可以多次使用同一个生命周期钩子函数,其执行顺序和书写顺序相同。

3.5 补充

首先是关于v-model语法糖调整:

  1. 在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />
  2. 在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

在实际应用中,常常用在父子组件通信中,通过在子组件身上绑定:modelValue="msg"来传递数据,子组件中则在适当的地方用emit('update:modelValue', xxx)更新数据(也可以理解为向父组件传递数据)。

其次是一些其它内容:

Vue3中的 computed、watch 和 watchEffect — 【Vue3基础】Vue3中的 computed、watch 和 watchEffect

Vue3 组件通信 — 【Vue3基础】Vue3 组件间通信

Vue3 Provide/Inject — 【Vue3基础】依赖注入 — Provide/Inject

Vue3 mixins —

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值