咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

Vue2迁移到Vue3:(二)“选项式API”和“组合式API”

Vue 3.x 引入了两种不同的组件编写风格:选项式 API 和组合式 API (新)。它们在语法和用法上存在一些区别。

选项式 API:

  1. 选项式 API 是 Vue 2.x 的传统编写风格,它使用 datamethodscomputedwatch 等选项来定义组件的数据、方法和响应式行为。
  2. 选项式 API 中,组件的逻辑和相关代码是分散在不同的选项中的,这使得代码组织和维护相对较为繁琐。
  3. 选项式 API 在简单组件和快速原型开发方面仍然是有效和方便的。

组合式 API:

  1. 组合式 API 是 Vue 3.x 中引入的新特性,它通过 setup 函数和一组新的函数式 API 来组织和重用组件逻辑。
  2. 组合式 API 中,你可以使用 setup 函数来定义组件的状态、计算属性、方法等。这些逻辑可以封装在一个函数中,提供更高的代码组织和可重用性。
  3. 组合式 API 允许你基于逻辑功能而不是选项进行组织,将相关代码放在一起,使得代码更易于理解和维护。
  4. 组合式 API 还提供了一些新的函数式 API,如 refreactivewatch 等,用于处理响应式数据、副作用和侦听等。

总结起来,选项式 API 是 Vue 2.x 的传统编写风格,适用于简单组件和快速开发。而组合式 API 是 Vue 3.x 引入的新特性,通过 setup 函数和一组新的函数式 API 提供了更高的代码组织和可重用性。

两种编写风格是互补的,你甚至可以在同一个项目中同时使用它们。

一、选项式API

Vue 3.x 保留了 选项式 API,以确保向后兼容性和平滑的迁移。

如果项目已经使用了选项式 API 或你更喜欢这种编写风格,你可以继续在 Vue 3.x 中使用选项式 API 来编写组件。

使用 选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script>
export default {
// data() 返回的属性将会成为响应式的状态
// 并且暴露在 `this` 上
data() {
return {
count: 0
}
},

// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件处理器绑定
methods: {
increment() {
this.count++
}
},

// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
mounted() {
console.log(`The initial count is ${this.count}.`)
}
}
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

count 放到 data 里面,当 count 的值变化,渲染也会响应式的更新。

二、组合式API

通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script setup>
import { ref, reactive , onMounted } from 'vue'

// 响应式状态
const count = ref(0)

// 创建一个响应式代理对象
//const state = reactive({ count: 0 });


// 用来修改状态、触发更新的函数
function increment() {
count.value++
}

// 生命周期钩子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

ref() 创建的是引用对象,需要 .value 访问;reactive() 创建的是响应式对象,可直接访问。

const count = ref(0) 类似 托管代理 的概念,这种风格在目前流行的 声明式UI 编程中频繁见到,比如:

  • Jetpack Compose 中 var count = remember{ mutableStateOf(0) }
  • ArkTs 中 @State count: int = 0
  • SwiftUI 中 @State var count = 0

从上面的示例,总结出,组合式API 优化了以下两点:

  1. ref() 替代 data(){} ,简洁了不少。
  2. 取消了 methods: {} ,直接写 function()

三、响应式基础

《响应式基础》

3.1 ref()

在组合式 API 中,推荐使用 ref() 函数来声明响应式状态:

1
2
3
import { ref } from 'vue'

const count = ref(0)

ref() 接收参数,并将其包裹在一个带有 .value 属性的 ref 对象中返回:

1
2
3
4
5
6
7
const count = ref(0)

console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

要在组件模板中访问 ref,请从组件的 setup() 函数中声明并返回它们:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { ref } from 'vue'

export default {
// `setup` 是一个特殊的钩子,专门用于组合式 API。
setup() {
const count = ref(0)

// 将 ref 暴露给模板
return {
count
}
}
}

<div>{{ count }}</div>


//注意:在模板中使用ref 无需附加 .value (在 JavaScript 中需要 .value )
<button @click="count++">
{{ count }}
</button>

在单文件(*.Vue)中简化代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
count.value++
}
</script>

<template>
<button @click="increment">
{{ count }}
</button>
</template>

3.2 reactive()

还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性:

1
2
3
import { reactive } from 'vue'

const state = reactive({ count: 0 })

在模板中使用:

1
2
3
<button @click="state.count++">
{{ state.count }}
</button>

reactive() 只能用于对象类型 (对象、数组和如 MapSet 这样的集合类型)。不能持有如 stringnumberboolean 这样的原始类型。