青少年编程与数学 02-006 前端开发框架VUE 04课题、组合式API
- [一、组合式 API](#一、组合式 API)
-
-
- [1. 函数式组织](#1. 函数式组织)
- [2. 响应式状态](#2. 响应式状态)
- [3. 生命周期钩子](#3. 生命周期钩子)
- [4. 依赖注入](#4. 依赖注入)
- [5. 逻辑复用性高](#5. 逻辑复用性高)
- [6. 代码可读性好](#6. 代码可读性好)
- [7. 更好的类型推断](#7. 更好的类型推断)
- [8. 常用的组合式 API 方法](#8. 常用的组合式 API 方法)
- [9. 跨组件通信](#9. 跨组件通信)
-
- [二、`setup` 函数](#二、
setup
函数) - [三、 `props` 对象](#三、
props
对象) -
-
- [定义 Props](#定义 Props)
- [访问 Props](#访问 Props)
- [使用 `toRefs` 转换 Props](#使用
toRefs
转换 Props) - 注意事项
-
- [四、`context` 对象](#四、
context
对象) -
-
- [什么是 `context` 对象](#什么是
context
对象) - [`context` 对象的属性和方法](#
context
对象的属性和方法) - [如何使用 `context` 对象](#如何使用
context
对象) - [`context` 对象的优势](#
context
对象的优势) - 注意事项
- [什么是 `context` 对象](#什么是
-
- 五、管理响应式状态
-
-
- [使用 `ref` 创建响应式基本类型数据](#使用
ref
创建响应式基本类型数据) - [使用 `reactive` 创建响应式对象](#使用
reactive
创建响应式对象) - [将 `reactive` 对象转换为 `ref` 对象](#将
reactive
对象转换为ref
对象) - 注意事项
- [使用 `ref` 创建响应式基本类型数据](#使用
-
- 六、响应式基础
-
- 声明响应式状态
-
- `ref()`
- [`<script setup>`](#
<script setup>
) - 计算属性的缓存机制
- 计算属性与方法的区别
- 总结
- 八、侦听器
- 九、生命周期钩子
-
-
- `onMounted`
- `onUpdated`
- `onUnmounted`
- `onBeforeMount`
- `onBeforeUpdate`
- `onBeforeUnmount`
- [`onActivated` 和 `onDeactivated`](#
onActivated
和onDeactivated
) - 注意事项
-
- 十、依赖注入
- 十一、应用示例
-
-
- [1. 初始化项目](#1. 初始化项目)
- [2. 创建 Todo 组件](#2. 创建 Todo 组件)
- [3. 在 `App.vue` 中使用 Todo 组件](#3. 在
App.vue
中使用 Todo 组件) - [4. 运行项目](#4. 运行项目)
-
课题摘要:本文介绍了Vue 3的组合式API,它通过
setup
函数组织组件逻辑,提升逻辑复用性和可维护性。组合式API支持响应式状态管理、生命周期钩子、依赖注入,使代码结构更清晰,易于维护。文章详细解释了setup
函数、props
对象、context
对象的用法,以及如何管理响应式状态、创建计算属性和侦听器。此外,还探讨了Vue 3的响应式基础、ref
和reactive
函数的使用方法,以及如何利用provide
和inject
实现跨组件通信。最后,通过一个Todo应用示例,展示了组合式API在实际项目中的应用。
本课程目的是概要地了解vue中的组合式API,详细内容后面将分解学习。
一、组合式 API
Vue 3 引入了组合式 API(Composition API),这是一种新的 API 风格,旨在提升组件的逻辑复用性和可维护性。以下是组合式 API 的一些关键特点和概念:
1. 函数式组织
组合式 API 主要通过 setup
函数来组织组件逻辑。所有的组合式 API 都在 setup
函数中使用,该函数在组件实例创建之前调用。
2. 响应式状态
通过 ref
和 reactive
创建响应式状态,使得组件的数据能够自动更新视图。
3. 生命周期钩子
使用 onMounted
、onUpdated
等函数来管理生命周期,替代了 Vue 2 中的 mounted
、updated
等选项。
4. 依赖注入
通过 provide
和 inject
来实现依赖注入,使得组件之间可以共享数据和方法。
5. 逻辑复用性高
组合式 API 允许开发者将相关的逻辑代码(如数据获取、状态管理、事件处理等)组合在一起,形成一个个独立的函数,这些函数可以在多个组件中复用。
6. 代码可读性好
在处理复杂组件逻辑时,组合式 API 可以让代码结构更清晰。将不同功能的逻辑(如数据监听、计算属性等)分别放在不同的函数或代码块中,而不是像选项式 API 那样分散在 data
、methods
、computed
等选项中,这样更便于理解和维护组件的功能。
7. 更好的类型推断
对于使用 TypeScript 的项目,组合式 API 提供了更好的类型推断支持。开发者可以更方便地为函数的参数和返回值定义类型,从而减少类型错误。
8. 常用的组合式 API 方法
ref
:用于创建响应式的基本类型数据。computed
:用于创建计算属性,依赖于其他响应式数据,并且只有在依赖发生变化时才会重新计算值。watch
和watchEffect
:用于侦听数据的变化并作出响应。- 生命周期钩子:如
onBeforeMount
、onMounted
等,用于替代 Options API 中的生命周期钩子。
9. 跨组件通信
Vue 3 提供了多种方式来实现跨组件通信,包括 props
、emit
、provide/inject
等。
组合式 API 的引入,使得 Vue 3 的组件编写更加灵活和模块化,特别适合处理复杂的逻辑和状态管理,同时也使得代码更加易于维护和理解。
二、setup
函数
Vue 3 的组合式 API 中的 setup
函数是一个非常重要的概念,它是组件的入口点,允许开发者以一种更灵活和组织化的方式编写组件逻辑。以下是 setup
函数的详细解释:
定义和作用
setup
函数是 Vue 3 中引入的一个新的组件选项,它是响应式组件的入口。- 它在组件实例创建之前执行,并且只能在定义组件时使用。
setup
函数提供了一个上下文对象,其中包含了组件的属性、插槽、属性和上下文(emit, attrs, slots, context)。
函数签名
setup
函数可以接收两个参数:
props
:一个包含所有传入组件的属性的对象。context
:一个对象,包含了以下属性:attrs
:包含所有未在props
中声明的属性绑定(v-bind
)。slots
:包含所有插槽。emit
:用于触发事件的函数。expose
:用于暴露公共实例属性的函数。root
:指向根实例的引用。
返回值
setup
函数可以返回任何类型的值,这些值将在模板或其他组件选项中使用。- 返回的基本类型值(如字符串、数字等)将被转换为一个响应式的
ref
对象。 - 返回的对象将自动转换为
setup
函数的响应式属性。
生命周期
setup
函数在组件实例化之前执行,并且只在组件的整个生命周期中执行一次。- 它在
beforeCreate
钩子之前执行,因此此时组件的data
、computed
和methods
还未被初始化。
使用场景
- 管理响应式状态:使用
ref
和reactive
创建响应式数据。 - 计算属性:使用
computed
创建依赖于响应式数据的计算属性。 - 侦听器:使用
watch
和watchEffect
侦听响应式数据的变化。 - 生命周期钩子:使用
onMounted
、onUpdated
等生命周期函数。 - 依赖注入:使用
provide
和inject
实现跨组件的状态共享。
示例
下面是一个简单的 setup
函数示例:
javascript
import { ref, onMounted } from 'vue';
export default {
setup(props, { attrs, slots, emit }) {
// 创建响应式数据
const count = ref(0);
// 创建计算属性
const doubledCount = computed(() => count.value * 2);
// 创建侦听器
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
});
// 使用生命周期钩子
onMounted(() => {
console.log('Component is mounted');
});
// 可以返回任何值,这些值将在模板中可用
return {
count,
doubledCount
};
}
};
在这个示例中,setup
函数创建了一个响应式数据 count
,一个计算属性 doubledCount
,并设置了一个侦听器来监听 count
的变化。同时,它还使用了一个生命周期钩子 onMounted
来在组件挂载后执行操作。最后,它返回了 count
和 doubledCount
,这些值可以在组件的模板中使用。
setup
函数是组合式 API 的核心,它提供了一种更灵活和组织化的方式来编写组件逻辑,使得代码更加模块化和可维护。
三、 props
对象
在 Vue 3 的组合式 API 中,props
对象并不是一个 API 或函数,而是组件的一个选项,它用于定义组件接受的外部传入的数据。在使用组合式 API 时,props
的处理方式与传统的选项式 API(Options API)有所不同。
定义 Props
在使用组合式 API 时,你仍然可以在组件中定义 props
,但是访问这些 props
的方式有所变化。在 setup
函数中,props
作为第一个参数传入,你可以直接使用这个参数。
javascript
import { defineComponent } from 'vue';
export default defineComponent({
props: {
message: String
},
setup(props) {
// 在这里,props 是一个对象,包含了所有传入的 props
console.log(props.message); // 访问传入的 props
// 你可以返回 props,使其在模板或其他组合式 API 中可用
return {
message: props.message
};
}
});
访问 Props
在 setup
函数中,props
对象包含了所有父组件传递给子组件的数据。你可以直接访问这些数据,就像访问普通 JavaScript 对象的属性一样。
使用 toRefs
转换 Props
由于 props
对象中的属性不是响应式的,如果你需要将 props
对象中的属性作为响应式引用(ref
)使用,可以使用 toRefs
函数将 props
对象转换为一个响应式的对象,其中每个属性都是一个 ref
。
javascript
import { toRefs } from 'vue';
export default {
setup(props) {
// 将 props 对象转换为响应式引用
const propsRefs = toRefs(props);
// 现在可以使用 propsRefs.message 作为响应式引用
return {
...propsRefs
};
}
};
注意事项
-
响应式 :在
setup
函数中直接使用props
对象时,它们不是响应式的。如果你需要响应式引用,使用toRefs
进行转换。 -
不可变 :
props
应该是不可变的,这意味着你不应该在子组件内部修改props
的值。 -
类型检查和验证 :你可以在
props
定义中指定类型和验证规则,Vue 会在开发模式下进行类型检查和验证。 -
与模板的集成 :在模板中使用
props
时,不需要任何特殊处理,直接使用即可。
通过以上方式,你可以在 Vue 3 的组合式 API 中有效地使用和管理 props
,使得组件之间的数据传递更加清晰和高效。
四、context
对象
在 Vue 3 的组合式 API 中,context
对象是一个非常有用的工具,它允许我们在 setup
函数中访问组件的上下文信息,包括组件的属性、事件、插槽等。以下是 context
对象的详细解释和使用指南:
什么是 context
对象
context
对象提供了对组件上下文的访问,包括但不限于 attrs
、slots
、emit
等属性和方法。这些属性和方法允许我们直接在 setup
函数中访问组件的非响应式属性、插槽和事件发射器,而不需要使用 this
关键字。
context
对象的属性和方法
-
attrs :包含了所有未被
props
属性消耗的属性绑定(即v-bind
绑定的属性),类似于 Options API 中的this.$attrs
。 -
slots :包含了组件的所有插槽,类似于 Options API 中的
this.$slots
。 -
emit :一个函数,用于触发父组件的事件,类似于 Options API 中的
this.$emit
。 -
expose:一个函数,用于暴露给父组件的响应式属性或方法,这样父组件就可以访问到子组件内部的响应式状态或方法。
如何使用 context
对象
在 setup
函数中,context
作为第二个参数传入,可以直接调用 context()
来获取 context
对象:
javascript
import { ref } from 'vue';
export default {
setup(props, context) {
const count = ref(0);
const emit = context.emit; // 获取 emit 方法
const increment = () => {
count.value++;
emit('increment'); // 触发事件
};
return {
count,
increment
};
}
};
context
对象的优势
-
简化代码 :
context
函数提供了一种更简洁的方式来访问组件的上下文信息,减少了在组件中使用this
的次数。 -
易于使用 :
context
函数使用起来非常简单,只需调用context
函数即可获取组件的上下文信息。 -
类型安全 :通过 TypeScript,可以为
context
函数添加类型注解,提高代码的类型安全性。
注意事项
-
避免过度使用 :虽然
context
非常有用,但过度使用可能会导致代码难以理解。应根据实际需求合理使用。 -
遵循最佳实践 :在编写 Vue 3 代码时,遵循最佳实践,如使用
context
函数等。
总结来说,context
对象是 Vue 3 组合式 API 中的一个核心功能,它使得我们可以更方便地访问组件的上下文信息,从而编写出更清晰、更易于维护的代码。
五、管理响应式状态
在 Vue 3 中,组合式 API 提供了 ref
和 reactive
两个函数来创建和管理响应式状态。以下是如何使用这两个函数的详细说明:
使用 ref
创建响应式基本类型数据
ref
函数用于创建一个响应式的引用(reference),它包装了一个值,使得这个值在 Vue 的响应式系统中是可跟踪的。这对于基本类型的数据(如字符串、数字、布尔值)特别有用。
javascript
import { ref } from 'vue';
const count = ref(0); // 创建一个响应式的数字
// 访问和修改 ref 的值需要使用 .value 属性
console.log(count.value); // 输出 0
count.value++; // 增加计数
在模板中使用 ref
:
vue
<template>
<div>{{ count }}</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
使用 reactive
创建响应式对象
reactive
函数用于创建一个响应式对象,它使得对象内的所有属性都是响应式的。
javascript
import { reactive } from 'vue';
const state = reactive({
count: 0,
name: 'Vue'
});
// 直接修改对象的属性即可
console.log(state.count); // 输出 0
state.count++; // 增加计数
在模板中使用 reactive
:
vue
<template>
<div>{{ state.count }} - {{ state.name }}</div>
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({
count: 0,
name: 'Vue'
});
</script>
将 reactive
对象转换为 ref
对象
当你需要将 reactive
对象的属性作为 ref
使用时,可以使用 toRefs
函数。这在你需要将 reactive
对象的属性单独作为 ref
传递给其他组件时非常有用。
javascript
import { reactive, toRefs } from 'vue';
const state = reactive({
count: 0,
name: 'Vue'
});
// 将 reactive 对象转换为 ref 对象
const stateRefs = toRefs(state);
// 现在 stateRefs.count 是一个 ref 对象
console.log(stateRefs.count.value); // 输出 0
注意事项
-
不可变数据结构 :Vue 3 不支持直接对数组或内置对象(如
Map
、Set
)使用ref
或reactive
来创建响应式数据。对于这些类型,你需要使用reactive
包装整个对象,然后操作对象内的数组或集合。 -
访问和修改 :访问
ref
创建的响应式数据时,需要通过.value
属性。修改时也直接操作.value
。 -
模板语法糖 :在模板中,Vue 提供了语法糖,允许你直接使用
ref
而不需要.value
,Vue 会自动解包。
通过 ref
和 reactive
,Vue 3 的组合式 API 提供了灵活的方式来创建和管理响应式状态,使得状态管理更加直观和高效。
六、响应式基础
本段内容来自官方文档。
声明响应式状态
ref()
在组合式 API 中,推荐使用 [ref()
] 函数来声明响应式状态:
js
js
import { ref } from 'vue'
const count = ref(0)
ref()
接收参数,并将其包裹在一个带有 .value
属性的 ref 对象中返回:
js
js
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
要在组件模板中访问 ref,请从组件的 setup()
函数中声明并返回它们:
js
js
import { ref } from 'vue'
export default {
// `setup` 是一个特殊的钩子,专门用于组合式 API。
setup() {
const count = ref(0)
// 将 ref 暴露给模板
return {
count
}
}
}
template
vue
<div>{{ count }}</div>
注意,在模板中使用 ref 时,我们不 需要附加 .value
。为了方便起见,当在模板中使用时,ref 会自动解包。
你也可以直接在事件监听器中改变一个 ref:
template
vue
<button @click="count++">
{{ count }}
</button>
对于更复杂的逻辑,我们可以在同一作用域内声明更改 ref 的函数,并将它们作为方法与状态一起公开:
js
js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
// 在 JavaScript 中需要 .value
count.value++
}
// 不要忘记同时暴露 increment 函数
return {
count,
increment
}
}
}
然后,暴露的方法可以被用作事件监听器:
template
vue
<button @click="increment">
{{ count }}
</button>
<script setup>
在 setup()
函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用[单文件组件 (SFC)来避免这种情况。我们可以使用 <script setup>
来大幅度地简化代码:
vue
js
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
### 设置 getter 和 setter
`computed` 也可以接受一个包含 `get` 和 `set` 函数的对象,这允许你创建一个可写的计算属性。
```javascript
import { computed, ref } from 'vue';
const count = ref(0);
const doubledCount = computed({
// getter
get: () => count.value * 2,
// setter
set: (newValue) => {
count.value = newValue / 2;
}
});
在这个例子中,doubledCount
既可以读取也可以设置。当设置 doubledCount
的值时,count
的值会相应地更新。
计算属性的缓存机制
计算属性是缓存的,只有当计算属性的响应式依赖发生变化时,计算属性才会重新计算。这意味着只要依赖项没有变化,多次访问计算属性会立即返回之前的计算结果,而不会再次执行计算函数。
计算属性与方法的区别
虽然你可以使用方法来执行类似的计算,但计算属性提供了缓存机制,这使得计算属性在依赖项未改变时更加高效。此外,计算属性的依赖项是自动跟踪的,而方法则需要手动处理依赖关系。
总结
computed
是 Vue 3 组合式 API 中一个强大的工具,它允许你创建依赖于响应式数据的缓存计算属性。这使得你可以构建复杂的逻辑,同时保持应用的性能和响应性。通过使用 computed
,你可以确保只有在必要时才重新计算值,从而优化你的应用性能。
八、侦听器
在 Vue 3 的组合式 API 中,watch
和 watchEffect
是两个用于侦听响应式数据变化的函数。它们允许你观察和响应 Vue 应用中的状态变化,这对于执行副作用(如数据获取、状态更新等)非常有用。
watchEffect
函数
watchEffect
函数会立即执行传入的函数,并在其依赖的响应式数据发生变化时重新执行。
基本用法:
javascript
import { ref, watchEffect } from 'vue';
const state = ref(0);
watchEffect(() => {
console.log(state.value); // 每当 state 发生变化时,这里的代码都会执行
});
在这个例子中,任何对 state
的修改都会触发 console.log
的执行。
参数:
watchEffect
可以接受一个函数作为参数,这个函数会在 watchEffect
被创建时立即执行一次,并且每当其依赖的响应式数据发生变化时再次执行。
返回值:
watchEffect
返回一个停止侦听的函数,你可以调用这个函数来停止侦听。
javascript
const stop = watchEffect(() => {
console.log(state.value);
});
// 稍后停止侦听
stop();
watch
函数
watch
函数用于侦听一个或多个响应式数据源,并在其变化时执行副作用。
基本用法:
javascript
import { ref, watch } from 'vue';
const state = ref(0);
watch(state, (newValue, oldValue) => {
console.log(`state从${oldValue}变化到${newValue}`); // 当 state 发生变化时,这里的代码都会执行
});
在这个例子中,watch
侦听了 state
的变化,并在变化时打印新旧值。
参数:
watch
接受两个参数:第一个是要侦听的响应式数据源,第二个是一个回调函数,该函数会在侦听的数据源变化时被调用。
选项:
watch
还接受一个可选的选项对象,其中可以配置立即执行(immediate
)、侦听深度(deep
)等。
javascript
watch(
() => state.value,
{
immediate: true, // 立即执行回调函数
deep: true // 深度侦听,对于对象和数组有效
},
(newValue, oldValue) => {
console.log(`state从${oldValue}变化到${newValue}`);
}
);
区别和选择
watchEffect
:自动侦听其依赖的响应式数据,并且没有新旧值的概念,它只是依赖发生变化时重新执行。watch
:允许你指定具体的响应式数据源,并在数据变化时提供新旧值,更灵活。
使用场景
watchEffect
:当你需要执行副作用,并且这个副作用依赖于多个响应式数据源时。watch
:当你需要在响应式数据变化时执行具体的逻辑,并且需要知道变化前后的值时。
通过使用 watch
和 watchEffect
,你可以在 Vue 3 的组合式 API 中有效地管理和响应状态变化,使得你的应用能够根据状态的变化执行相应的操作。
九、生命周期钩子
在 Vue 3 的组合式 API 中,生命周期钩子函数允许你在组件的不同阶段执行代码。这些生命周期钩子函数与选项式 API 中的生命周期钩子相对应,但它们专为 setup
函数设计,使得在组合式 API 中管理组件的生命周期变得更加直接和灵活。
以下是 Vue 3 组合式 API 提供的一些主要生命周期钩子函数:
onMounted
onMounted
钩子函数在组件的 DOM 挂载完成后被调用。这与选项式 API 中的 mounted
钩子相对应。
基本用法:
javascript
import { onMounted } from 'vue';
export default {
setup() {
onMounted(() => {
console.log('组件已挂载到 DOM');
// 执行 DOM 操作或执行副作用
});
}
};
onUpdated
onUpdated
钩子函数在组件更新后被调用,这包括响应式数据的变化导致的重新渲染。这与选项式 API 中的 updated
钩子相对应。
基本用法:
javascript
import { onUpdated } from 'vue';
export default {
setup() {
onUpdated(() => {
console.log('组件已更新');
// 响应组件更新
});
}
};
onUnmounted
onUnmounted
钩子函数在组件卸载和销毁之前被调用。这与选项式 API 中的 beforeDestroy
和 destroyed
钩子相对应。
基本用法:
javascript
import { onUnmounted } from 'vue';
export default {
setup() {
onUnmounted(() => {
console.log('组件即将卸载');
// 清理工作,如取消订阅、定时器等
});
}
};
onBeforeMount
onBeforeMount
钩子函数在组件挂载之前被调用,此时组件的模板已经渲染为 HTML,但还没有被添加到 DOM 中。
基本用法:
javascript
import { onBeforeMount } from 'vue';
export default {
setup() {
onBeforeMount(() => {
console.log('组件即将挂载');
// 执行挂载前的准备工作
});
}
};
onBeforeUpdate
onBeforeUpdate
钩子函数在组件更新之前被调用。
基本用法:
javascript
import { onBeforeUpdate } from 'vue';
export default {
setup() {
onBeforeUpdate(() => {
console.log('组件即将更新');
// 执行更新前的准备工作
});
}
};
onBeforeUnmount
onBeforeUnmount
钩子函数在组件卸载之前被调用。
基本用法:
javascript
import { onBeforeUnmount } from 'vue';
export default {
setup() {
onBeforeUnmount(() => {
console.log('组件即将卸载');
// 执行卸载前的准备工作
});
}
};
onActivated
和 onDeactivated
这两个钩子函数用于保持活动状态的组件(如 <keep-alive>
缓存的组件)。
基本用法:
javascript
import { onActivated, onDeactivated } from 'vue';
export default {
setup() {
onActivated(() => {
console.log('组件被激活');
});
onDeactivated(() => {
console.log('组件被停用');
});
}
};
注意事项
- 生命周期钩子函数应该在
setup
函数中调用,因为它们依赖于组合式 API 的响应式系统。 - 生命周期钩子函数提供了一种在组件的不同阶段执行代码的机制,使得组件的控制更加灵活和精确。
- 使用生命周期钩子函数时,确保不要在函数中执行异步操作而忘记清理,这可能会导致内存泄漏。
通过这些生命周期钩子函数,你可以更好地控制组件的生命周期,执行必要的初始化和清理工作,以及响应组件状态的变化。
十、依赖注入
在 Vue 3 中,provide
和 inject
是一对函数,它们允许跨组件树进行状态共享,而不必通过每个层级的组件逐级传递 props。这种依赖注入的模式非常适合于需要在多个不直接相关的组件之间共享状态的场景。
provide
provide
函数用于向所有子孙组件提供数据。它应该在组件的 setup
函数中调用,并且可以提供任何可响应式的数据或方法。
基本用法:
javascript
import { provide, reactive } from 'vue';
export default {
setup() {
const state = reactive({
theme: 'dark',
toggleTheme: () => {
state.theme = state.theme === 'dark' ? 'light' : 'dark';
}
});
provide('themeState', state); // 提供响应式状态
return {
state
};
}
};
在这个例子中,state
对象被提供给所有子孙组件,它们可以通过 inject
函数访问 theme
和 toggleTheme
方法。
inject
inject
函数用于接收从祖先组件提供的响应式数据。它应该在组件的 setup
函数中调用。
基本用法:
javascript
import { inject } from 'vue';
export default {
setup() {
const themeState = inject('themeState'); // 接收提供的状态
if (!themeState) {
console.error('themeState is not provided');
}
return {
themeState
};
}
};
在这个例子中,组件接收了祖先组件提供的 themeState
对象,并将其作为响应式数据使用。
provide
和 inject
的选项
provide
和 inject
都可以接受第二个参数,这是一个选项对象,允许你定义默认值和是否允许注入为 undefined
。
javascript
// 提供默认值
provide('themeState', state, { default: () => ({}) });
// 允许注入为 undefined
provide('themeState', state, { from: 'parent', default: null });
注意事项
-
响应式 :
provide
和inject
都支持响应式数据,但inject
接收的是非响应式的副本,如果需要响应式引用,可以使用inject
的响应式版本injectReactive
。 -
祖先组件 :
provide
必须在其子孙组件的祖先组件中调用,否则inject
将无法接收到提供的值。 -
跨组件通信 :
provide
和inject
是跨组件通信的一种方式,适用于需要在多个层级间共享状态的场景。 -
命名冲突:避免使用相同的键在不同的祖先组件中提供不同的值,这可能会导致命名冲突。
-
清理 :由于
provide
和inject
建立的是响应式连接,所以在组件卸载时,Vue 会自动处理这些连接的清理工作。
通过使用 provide
和 inject
,你可以在 Vue 3 的组合式 API 中实现跨组件的状态共享,使得状态管理更加集中和高效。
十一、应用示例
创建一个 Vue 3 项目实例,这个项目将是一个简单的待办事项(Todo)应用。我们将使用 ref
、reactive
、computed
、watch
和生命周期钩子来构建这个应用。
1. 初始化项目
使用 Vite 创建一个新的 Vue 3 项目:
bash
npm create vite@latest my-todo-app -- --template vue
cd my-todo-app
npm install
2. 创建 Todo 组件
在 src
目录下创建一个新的组件文件 TodoList.vue
:
vue
<template>
<div>
<h1>Todo List</h1>
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="Add a new todo">
<ul>
<li v-for="todo in filteredTodos" :key="todo.id">
<input type="checkbox" v-model="todo.completed">
<span :class="{ 'completed': todo.completed }">{{ todo.task }}</span>
<button @click="removeTodo(todo.id)">Remove</button>
</li>
</ul>
<button @click="toggleFilter">Show {{ filter === 'all' ? 'All' : 'Active' }} Todos</button>
<p>Active Todos: {{ activeTodos.length }}</p>
</div>
</template>
<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue';
// 使用 reactive 创建响应式状态对象
const state = reactive({
todos: [],
newTodo: '',
filter: 'all',
});
// 使用 ref 创建单个响应式引用
const nextTodoId = ref(0);
// 计算属性,过滤待办事项
const filteredTodos = computed(() => {
if (state.filter === 'all') {
return state.todos;
} else {
return state.todos.filter(todo => !todo.completed);
}
});
// 计算属性,计算活跃待办事项的数量
const activeTodos = computed(() => {
return state.todos.filter(todo => !todo.completed);
});
// 监听新待办事项输入框的变化
watch(() => state.newTodo, (newVal) => {
if (newVal === '') {
// 如果输入框为空,则重置下一个待办事项的 ID
nextTodoId.value = 0;
}
});
// 生命周期钩子,组件挂载后执行
onMounted(() => {
console.log('TodoList component is mounted');
});
// 方法,添加新的待办事项
function addTodo() {
if (state.newTodo.trim()) {
state.todos.push({
id: nextTodoId.value++,
task: state.newTodo,
completed: false,
});
state.newTodo = '';
}
}
// 方法,移除待办事项
function removeTodo(id) {
state.todos = state.todos.filter(todo => todo.id !== id);
}
// 方法,切换过滤条件
function toggleFilter() {
state.filter = state.filter === 'all' ? 'active' : 'all';
}
</script>
<style scoped>
.completed {
text-decoration: line-through;
}
</style>
3. 在 App.vue
中使用 Todo 组件
编辑 src/App.vue
文件,引入并使用 TodoList
组件:
vue
<template>
<div id="app">
<TodoList />
</div>
</template>
<script>
import TodoList from './components/TodoList.vue';
export default {
name: 'App',
components: {
TodoList
}
};
</script>
<style>
/* 全局样式 */
</style>
4. 运行项目
使用以下命令启动开发服务器:
bash
npm run dev
现在,你可以在浏览器中访问 http://localhost:3000
来查看你的 Vue 3 Todo 应用。
这个项目实例展示了如何使用 Vue 3 的组合式 API 来创建一个待办事项应用。它包括了 ref
、reactive
、computed
、watch
和生命周期钩子的使用。这个应用允许用户添加、删除待办事项,并可以过滤显示所有或活跃的待办事项。你可以根据需要扩展这个项目,添加更多的功能,比如编辑待办事项、保存待办事项到本地存储等。