一、Vue 3 概述
1. 为什么要学习Vue 3
Vue 3是Vue.js的最新主要版本,它带来了许多改进和新特性,包括但不限于:
- 性能提升:Vue 3提供了更快的渲染速度和更低的内存使用率。
- Composition API:引入了一个新的API,允许更灵活的代码组织和复用,特别适合构建大型应用。
- 更好的TypeScript支持:Vue 3从头开始就考虑了TypeScript的支持,使得使用TypeScript开发Vue应用更加顺畅。
- 更小的体积:通过优化和树摇(tree-shaking),Vue 3的体积更小,使得加载时间更短。
学习Vue 3可以让你利用最新的Web开发技术构建高效、可维护的前端应用。
2. Vue 3的新变化
Vue 3带来了很多重要的新变化,包括:
- Composition API:提供了一种新的方式来组织组件的逻辑,使得功能更容易被提取和复用。
- 响应式系统的重写:使用Proxy对象重写了响应性系统,提高了性能并减少了内存占用。
- 片段(Fragments):组件可以有多个根节点,而不再限于单一根节点。
- Teleport组件:允许将子节点渲染到DOM树的其他位置。
- Suspense组件:提供了一种新的方式来处理异步组件的加载状态。
3. 破坏性语法的更新
Vue 3也引入了一些破坏性更新,以提高性能和开发体验,比如:
- 废除了一些不再推荐使用的API,如
Vue.extend
、Vue.mixin
等。 - EventBus的使用方式发生了变化,推荐使用提供/注入(provide/inject)模式或是Vuex来进行全局状态管理。
接下来,让我们用一个简单的示例开始Vue 3的旅程:
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Vue 3 Hello World</title></head><body><divid="app">{{ message }}</div><scriptsrc="https://unpkg.com/[email protected]"></script><script>const{ createApp }= Vue;createApp({data(){return{message:'Hello Vue 3!'}}}).mount('#app');</script></body></html>
这个示例创建了一个最基本的Vue 3应用,展示了如何使用
createApp
方法创建一个新的Vue应用,并将其挂载到页面上的指定元素。
二、Vue 3 开发环境搭建
搭建Vue 3开发环境是开始学习和开发Vue 3应用的第一步。
这一部分将引导你如何创建Vue 3项目,并简要介绍项目结构的变化。
1. 创建Vue 3项目
Vue 3项目可以通过Vue CLI或Vite这两种方式创建。Vue CLI是Vue的官方命令行工具,而Vite是一个现代化的前端构建工具,提供了更快的开发服务器启动和热重载。
使用Vue CLI创建项目:
首先,确保你安装了最新版的Vue CLI。如果尚未安装,可以通过npm安装:
npminstall-g @vue/cli
然后,创建一个新的Vue 3项目:
vue create my-vue-app
在创建过程中,CLI会让你选择预设配置。为了使用Vue 3,你可以选择“Manually select features”来自定义功能,确保选择了“Vue 3”选项。
使用Vite创建项目:
Vite是一个建立在现代Web标准之上的新一代前端构建工具。使用Vite创建Vue 3项目,可以获得极速的服务启动和模块热更新。安装Vite并创建一个新项目:
npm init vite@latest my-vue-app -- --template vue
接下来,进入项目目录并安装依赖:
cd my-vue-app
npminstall
2. 创建Vue 2和Vue 3项目的文件变化
Vue 3项目的文件结构在大体上保持了与Vue 2类似的结构,但也有一些关键的变化和改进:
- **
main.js
**:Vue 3使用createApp
函数来创建一个Vue应用实例,而Vue 2使用new Vue()
构造函数。 - 单文件组件(
.vue
文件):在Vue 3中,<script setup>
语法糖允许更简洁的组合式API代码,使得组件的编写更加高效。
3. Vue 3中的App单文件不再强制要求必须有根元素
在Vue 2中,每个单文件组件(.vue文件)必须有一个单独的根元素。而在Vue 3中,这一限制被取消,允许组件有多个根元素,这为组件的布局提供了更大的灵活性。
示例代码:创建Vue 3项目
以下是一个简单的Vue 3项目的
main.js
示例,演示了如何使用
createApp
来创建一个Vue应用:
import{ createApp }from'vue';import App from'./App.vue';createApp(App).mount('#app');
这里,
App.vue
是根组件,它可以是这样的:
<template>
<div>Hello Vue 3!</div>
<div>This is a multi-root component!</div>
</template>
<script>
export default {
name: 'App'
}
</script>
三、组合式API(Composition API)和选项式API(Options API)
Vue 3引入了一个新的API——组合式API(Composition API),这是一个重大的创新,旨在解决在使用Vue 2中的选项式API(Options API)时遇到的一些限制,尤其是在处理大型和复杂组件时。我们来看看这两种API的主要差异和它们的应用场景。
选项式API(Options API)
在Vue 2中,我们主要通过选项式API来组织组件的代码,比如
data
,
methods
,
props
,
computed
,
watch
等选项。这种方式很直观,因为它将不同类型的组件选项分门别类地组织起来。
<template>
<div>{{ fullName }}</div>
</template>
<script>
export default {
data() {
return {
firstName: 'Jane',
lastName: 'Doe'
}
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
}
</script>
组合式API(Composition API)
Vue 3的组合式API提供了一种更灵活的组织组件逻辑的方式。它通过
setup()
函数允许你将相关功能组织在一起,而不是基于选项类型分开。这使得代码重用和逻辑提取变得更加简单,尤其是在构建复杂组件时。
<template>
<div>{{ fullName }}</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const firstName = ref('Jane');
const lastName = ref('Doe');
const fullName = computed(() => firstName.value + ' ' + lastName.value);
return { fullName };
}
}
</script>
API比较
- 代码组织:组合式API使得按逻辑组织代码变得更加容易,特别是在处理复杂组件时,可以将相关的逻辑放在一起,而不是分散在不同的选项中。
- 类型推断:组合式API提供了更好的TypeScript集成,因为它能够利用TypeScript的类型推断,使得在使用TypeScript开发Vue应用时更加顺畅。
- 代码复用:通过组合式API,可以更容易地将组件逻辑抽取到可复用的函数中,这对于保持代码的干净和维护性是非常有帮助的。
示例代码:使用Composition API
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
}
}
</script>
这个例子展示了如何使用
ref
来创建一个响应式的计数器,以及如何将逻辑(如增加计数)组织在
setup
函数中。
组合式API和选项式API各有优势,Vue 3提供了这两种API,以便开发者可以根据具体项目和个人偏好选择最适合的方式。
四、组合式API(Composition API)
Vue 3的组合式API是一组基于函数的API,让你能够更灵活地组织和重用组件逻辑。通过组合式API,你可以更容易地将组件逻辑按功能组织,而不是分散在不同的Vue选项中。下面我们来详细看看组合式API的核心特性。
1. setup函数
setup
函数是组合式API的入口点,它在组件创建之前执行,此时组件的props已经解析完成。你可以在这个函数里定义响应式状态、计算属性和函数,然后返回它们,使其在模板中可用。
示例代码:
<template>
<div>{{ message }}</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const message = ref('Hello Vue 3!');
// 返回的对象中的属性和函数在模板中可用
return { message };
}
}
</script>
在这个例子中,我们使用
ref
函数创建了一个响应式的数据
message
,并在模板中使用它。
2. 生命周期钩子
在组合式API中,你可以使用特定的函数来访问组件的生命周期钩子,这些函数名称以
on
开头,例如
onMounted
、
onUpdated
、
onUnmounted
等。
示例代码:
<script>
import { onMounted, ref } from 'vue';
export default {
setup() {
const count = ref(0);
onMounted(() => {
console.log('Component is mounted!');
});
return { count };
}
}
</script>
这个例子展示了如何在组件挂载完成后使用
onMounted
生命周期钩子。
组合式API的优势在于它提供了更大的灵活性和逻辑复用的能力。使用
setup
函数,你可以按照逻辑而不是选项类型来组织代码,这在管理大型或复杂组件时特别有用。同时,通过直接使用生命周期钩子的函数,你可以更直接地控制组件的行为。
接下来,我们将探讨组合式API中的响应式引用(
ref
)和响应式对象(
reactive
),这两个是组合式API中最常用的响应式状态管理工具。
五、响应式Ref函数
在Vue 3的组合式API中,
ref
函数用于创建一个响应式的引用对象。这个对象内部有一个
.value
属性,通过这个属性可以获取或设置该引用的值。
ref
是处理基本数据类型(如字符串、数字、布尔值)的响应式状态时非常有用的工具。
1. 不使用
ref
函数
在不使用
ref
的情况下,如果你尝试直接在
setup
函数内使用基本类型的数据,那么这些数据不会是响应式的。这意味着当数据变化时,视图不会自动更新。
let count =0;// 这不是响应式的
2. 使用
ref
函数
使用
ref
可以让基本数据类型变成响应式的。这是因为
ref
返回的是一个响应式对象,我们通过操作这个对象的
.value
属性来读写实际的值。
示例代码:
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
}
}
</script>
在这个示例中,
count
是通过
ref
创建的响应式引用。我们在模板中直接使用
count
而不是
count.value
,Vue内部会自动处理这些引用。但是在JavaScript逻辑中,我们通过
count.value
来读写这个值。
3.
ref
引用
ref
不仅可以用于基本数据类型,也可以用于引用类型数据(如对象或数组)。当用于引用类型时,Vue会递归地将这些数据转换为响应式数据。
示例代码:
<script>
import { ref } from 'vue';
export default {
setup() {
const state = ref({
count: 0,
message: "Hello"
});
function increment() {
state.value.count++;
}
return { state, increment };
}
}
</script>
在这个例子中,
state
是一个包含多个属性的对象。通过
ref
创建的响应式引用,我们可以保持对这个对象内部属性的响应式更新。
通过使用
ref
,Vue 3的组合式API使状态管理变得简单而直接,无论是基本数据类型还是引用类型数据。
ref
是构建响应式数据的基础,是理解和使用Vue 3必须掌握的概念之一。
接下来,我们将讨论
reactive
函数,它是另一个在Vue 3中管理响应式状态的重要工具,特别适用于复杂的对象。
六、Reactive函数
在Vue 3的组合式API中,除了
ref
之外,
reactive
函数是另一个核心功能,用于创建响应式的复杂数据结构,如对象或数组。
reactive
提供了一种更自然的方式来处理对象和数组,使其成为响应式数据,而无需使用
.value
属性进行访问。
使用
reactive
函数
reactive
接收一个普通对象并返回该对象的响应式代理。与
ref
不同,当你修改使用
reactive
创建的对象的属性时,不需要使用
.value
。
示例代码:
<template>
<div>{{ state.count }}</div>
<button @click="increment">Increment</button>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
count: 0
});
function increment() {
state.count++;
}
return { state, increment };
}
}
</script>
在这个例子中,我们创建了一个响应式对象
state
,并在模板中直接使用了它的属性。这比使用
ref
更加直接,尤其是在处理复杂对象时。
对比
ref
和
reactive
- 基本类型:
ref
适用于基本数据类型,可以通过.value
进行读写。reactive
不能直接用于基本数据类型。 - 引用类型:
reactive
直接作用于对象或数组,使其成为响应式。对于复杂的数据结构,reactive
比ref
更加适用。 - 模板中的使用:无论是
ref
还是reactive
创建的响应式数据,都可以直接在模板中使用,Vue 会自动处理。
深度响应式和浅响应式
- 默认情况下,
reactive
会递归地把一个对象内部的所有属性都转换为响应式数据。 - 浅响应式:如果你不希望对象内部的所有属性都是响应式的,可以使用
shallowReactive
函数,它只会使最外层的属性成为响应式,而不会影响嵌套对象。
import{ shallowReactive }from'vue';const state =shallowReactive({innerObject:{count:0}});// `state`是响应式的,但`state.innerObject`不是响应式的。
reactive
和
ref
是Vue 3中组合式API的两大支柱,理解它们之间的差异以及如何选择使用它们,对于高效开发Vue 3应用至关重要。
接下来,我们将讨论
toRefs
函数,它允许我们从
reactive
对象中提取出多个响应式引用,以保持结构分解赋值的响应性。
七、toRefs函数
在Vue 3的组合式API中,
toRefs
函数用于将
reactive
对象转换为一个普通对象,其中每个属性都是一个
ref
,这对于保持响应式状态在结构分解赋值(destructuring)时特别有用。
为什么需要
toRefs
当你从
reactive
对象中结构出属性时,这些属性会失去响应性。这是因为结构赋值是基于值的拷贝,所以拷贝出来的值不会和原始的
reactive
对象保持响应连接。
toRefs
可以解决这个问题,它允许你在结构分解时保持属性的响应性。
示例代码:
假设我们有一个
reactive
对象:
import{ reactive, toRefs }from'vue';exportdefault{setup(){const state =reactive({count:0,message:"Hello Vue 3"});// 尝试直接结构,会导致失去响应性// let { count, message } = state;// 使用toRefs来保持响应性let{ count, message }=toRefs(state);return{ count, message };}}
如何使用
toRefs
toRefs
接收一个响应式对象,并返回一个新的对象。返回的对象中的每个属性都是一个指向原始对象相应属性的
ref
。
<template>
<div>{{ count }}</div>
<div>{{ message }}</div>
</template>
在模板中,你可以直接使用
count
和
message
,就像它们是使用
ref
创建的响应式引用一样。这保证了即使在结构分解后,你依然可以保持组件的响应性。
toRefs
与
ref
toRefs
适用于将reactive
对象转换成一个包含多个ref
属性的普通对象,每个ref
都是响应式的。ref
用于创建单个响应式数据。
使用
toRefs
可以非常方便地在保持响应性的同时,使用JavaScript的结构分解功能,这对于在多个地方使用或传递
reactive
对象的部分属性时非常有用。
到目前为止,我们已经讨论了Vue 3的组合式API中的基本响应式API——
ref
、
reactive
和
toRefs
。这些工具为开发复杂组件提供了灵活性和强大的状态管理能力。
接下来,我们将进一步探讨Vue 3中的计算属性(
computed
)和侦听器(
watch
)。这些功能使得我们可以更细致地控制响应式状态的变化和更新。
八、Computed计算属性
在Vue 3中,计算属性(
computed
)是一种基于响应式依赖进行缓存的计算值。当计算属性依赖的响应式状态发生变化时,计算属性会重新计算。这非常适合用于执行开销较大的计算操作或派生状态。
1. 基本用法
使用
computed
函数可以创建一个计算属性。
computed
接收一个函数作为参数,这个函数的返回值就是计算属性的值。当依赖的响应式状态改变时,这个函数会被重新执行。
示例代码:
<template>
<div>{{ fullName }}</div>
</template>
<script>
import { reactive, computed } from 'vue';
export default {
setup() {
const person = reactive({
firstName: 'John',
lastName: 'Doe'
});
const fullName = computed(() => {
return `${person.firstName} ${person.lastName}`;
});
return { fullName };
}
}
</script>
在这个例子中,
fullName
是一个计算属性,它依赖于
reactive
对象
person
的
firstName
和
lastName
。当
person
的属性改变时,
fullName
会自动更新。
2. 高级用法
computed
也支持一个带有
get
和
set
函数的对象,允许你创建可写的计算属性。这在需要执行额外逻辑来处理更新操作时非常有用。
示例代码:
<template>
<div>{{ fullName }}</div>
<button @click="changeName">Change Name</button>
</template>
<script>
import { reactive, computed } from 'vue';
export default {
setup() {
const person = reactive({
firstName: 'John',
lastName: 'Doe'
});
const fullName = computed({
get() {
return `${person.firstName} ${person.lastName}`;
},
set(newValue) {
const names = newValue.split(' ');
person.firstName = names[0];
person.lastName = names[1] || '';
}
});
function changeName() {
fullName.value = 'Jane Doe';
}
return { fullName, changeName };
}
}
</script>
在这个高级用法中,我们定义了一个可写的计算属性
fullName
。当尝试设置
fullName.value
时,设置函数(setter)会被调用,允许我们将一个新值分解并赋值给
person.firstName
和
person.lastName
。
计算属性是Vue响应系统的重要部分,它使得管理复杂逻辑和依赖变得简单高效。
接下来,我们将探讨Vue 3中的侦听器(
watch
和
watchEffect
),它们提供了一种方法来响应数据的变化。
九、Watch监听
Vue 3的组合式API提供了
watch
和
watchEffect
两种方式来侦听响应式数据的变化,并执行相应的副作用。这两种API都非常强大,可以用于执行数据变化时的异步操作、资源清理或复杂的业务逻辑。
1. 单个数据监听 -
watch
watch
函数用于侦听单个或多个响应式引用(
ref
)或响应式对象(
reactive
)的属性,并在它们变化时执行回调函数。
watch
的回调函数接收新值和旧值作为参数。
示例代码:
<template>
<div>{{ count }}</div>
<button @click="increment">Increment</button>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
});
function increment() {
count.value++;
}
return { count, increment };
}
}
</script>
在这个例子中,每当
count
的值变化时,我们都会在控制台打印出一条消息。
2. 多个数据监听
watch
也可以同时侦听多个数据源。你需要将它们放在一个数组里,并在回调函数中接收一个数组形式的新值和旧值。
watch([ref1, ref2],([newVal1, newVal2],[oldVal1, oldVal2])=>{// 响应变化});
3. 复杂数据类型监听
对于复杂数据类型,如使用
reactive
创建的响应式对象,你可能希望在嵌套属性变化时也能触发侦听器。这时,可以直接将响应式对象传递给
watch
,Vue会进行深度监听。
4. 监听复杂数据类型中的属性
如果你只想监听响应式对象的某个属性,可以使用一个函数来返回这个属性的值。
watch(()=> state.someNestedProperty,(newValue, oldValue)=>{// 响应变化});
5. 开启深度监听
使用
watch
侦听响应式对象时,默认情况下不会深度侦听。如果需要深度侦听,可以通过传递一个配置对象,将
deep
属性设置为
true
。
watch(
state,(newValue, oldValue)=>{// 深度响应变化},{deep:true});
watchEffect
的使用
watchEffect
函数会立即执行传递给它的回调函数,并响应式地追踪回调函数中使用的任何响应式状态的变化。当依赖的响应式状态发生变化时,
watchEffect
会再次执行。
<script>
import { ref, watchEffect } from 'vue';
export default {
setup() {
const count = ref(0);
watchEffect(() => console.log(count.value));
return { count };
}
}
</script>
watch
和
watchEffect
提供了灵活且强大的方式来对响应式数据的变化作出反应,它们是Vue组合式API中不可或缺的一部分。
接下来,如果你准备好了,我们可以讨论Vue 3中组件之间的通信,包括父子通信和提供/注入机制。
十、父子通信
在Vue 3中,组件之间的通信是构建应用时的关键部分。Vue 提供了多种方式来实现不同场景下的组件通信,包括但不限于props、自定义事件、提供/注入机制等。我们首先讨论最常见的父子通信方式。
1. 父传子 - Props
Props是父组件向子组件传递数据的主要方式。子组件需要显式声明它期望接收的props。
子组件(ChildComponent.vue):
<!-- 子组件 --><template><div>{{ parentMessage }}</div></template><script setup>
const props = defineProps({
parentMessage: String
});</script>
<!-- 父组件 --><template><div><ChildComponent :parentMessage="message" /></div></template><script setup>import{ ref } from 'vue';import ChildComponent from './ChildComponent.vue';
const message = ref('Hello from parent');</script>
在这个例子中,父组件通过
message
prop向
ChildComponent
传递了一个字符串。
2. 子传父 - 自定义事件
子组件可以通过触发事件来向父组件传递信息。Vue 3中,使用
$emit
方法触发事件已被废弃,推荐使用
defineEmits
或
context.emit
。
子组件(ChildComponent.vue):
<template>
<button @click="notifyParent">Click Me</button>
</template>
<script>
import { defineEmits } from 'vue';
export default {
setup() {
const emit = defineEmits(['custom-event']);
function notifyParent() {
emit('custom-event', 'Some data');
}
return { notifyParent };
}
}
</script>
父组件:
<template>
<ChildComponent @custom-event="handleCustomEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleCustomEvent(data) {
console.log(data); // 输出: Some data
}
}
}
</script>
在这个例子中,子组件通过触发
custom-event
事件,并传递数据来与父组件通信。父组件监听这个事件,并定义了一个处理函数
handleCustomEvent
来接收数据。
这两种方法是Vue中实现父子通信的基础。通过Props,父组件可以向子组件传递数据,而通过自定义事件,子组件可以向父组件发送消息。
Vue还提供了更高级的通信方式,如提供/注入机制,它允许祖先组件向所有子孙组件传递数据,而无需通过每一层的props来显式传递。
十一、Vue 3中的指令变化
Vue 3引入了一些新指令并更新了一些现有指令的用法,以提高开发效率和应用性能。这里我们重点讨论
v-model
和
v-if
系列指令的变化。
1.
v-model
的变化
在Vue 2中,
v-model
主要用于在表单控件和应用状态之间创建双向数据绑定。Vue 3扩展了
v-model
的用法,允许在自定义组件上使用多个
v-model
绑定。
Vue 2用法:
<input v-model="message" />
Vue 3用法:
Vue 3允许自定义组件上使用多个
v-model
:
<CustomComponent v-model:title="pageTitle" v-model:content="pageContent" />
在自定义组件内部,可以通过
defineProps
来接收这些属性:
<script setup>
const props = defineProps({
title: String,
content: String
});
</script>
并使用
emit
来更新这些属性:
const emit =defineEmits(['update:title','update:content']);
2.
v-if
、
v-else-if
、
v-else
的使用
这一系列的指令在Vue 3中保持不变,用于条件渲染。
v-if
和
v-else-if
需要跟一个表达式,
v-else
不需要。这三个指令必须紧跟在彼此后面使用。
<template>
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else>C</div>
</template>
这些更新和变化反映了Vue 3在灵活性和功能性方面的提升,使得开发者能够更有效地构建复杂且高性能的应用。
Vue 3还引入了其他的新特性和API改进,包括
Teleport
、
Suspense
以及对Composition API的进一步增强。
十二、Vue 3中的TypeScript支持
Vue 3从一开始就把TypeScript支持作为其核心特性之一。这意味着Vue 3不仅能够提供更好的类型推断和代码智能提示,而且还能让开发者利用TypeScript的全部功能来构建应用。这种一流的TypeScript支持为开发大型应用和提高代码质量带来了巨大的好处。
类型增强
Vue 3利用Composition API提供了更好的类型推断。当你使用
ref
、
reactive
等API时,Vue 3能够准确地推断出相应的类型,这使得在使用TypeScript开发应用时能够获得更为准确的代码提示和类型检查。
示例代码:
<script lang="ts">import{ defineComponent, ref, Ref }from'vue';exportdefaultdefineComponent({setup(){const count: Ref<number>=ref(0);// `count`被推断为一个数字类型的响应式引用functionincrement(){
count.value++;}return{ count, increment };}});</script>
在这个例子中,我们明确声明了
count
是一个数字类型的响应式引用(
Ref<number>
)。这种类型声明让TypeScript能够提供准确的类型检查和代码提示。
使用
defineComponent
进行类型推断
Vue 3推荐使用
defineComponent
函数来定义组件,这不仅使得组件支持TypeScript,而且还能提供更好的类型推断和组件选项的类型检查。
<script lang="ts">import{ defineComponent }from'vue';exportdefaultdefineComponent({
props:{
message: String
},setup(props){console.log(props.message);// `props.message`被正确推断为`string`}});</script>
通过
defineComponent
,Vue 3可以准确地推断
props
、
data
、
computed
等选项的类型,大大提高了开发体验。
十三 Suspense
Vue 3引入的
Suspense
组件是一个用于处理异步组件加载和异步数据的特殊内置组件。它提供了一种新的方式来处理在等待异步操作完成时的UI渲染,特别适用于控制如数据获取、异步组件(或其依赖)加载等场景的用户体验。
工作原理
当一个组件需要进行异步操作,比如数据请求或异步导入另一个组件时,
Suspense
允许你定义一个“备用”内容(例如加载指示器),在异步操作完成之前显示。这意味着你可以提供一个平滑的用户体验,避免在数据加载时显示一个空白或不完整的页面。
基本用法
Suspense
通过两个插槽来工作:
- default 插槽:包含异步加载的组件。
- fallback 插槽:在等待异步操作完成时显示的内容。
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script>
import { defineAsyncComponent } from 'vue';
export default {
components: {
AsyncComponent: defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
}
}
</script>
在这个例子中,
AsyncComponent
是通过
defineAsyncComponent
定义的一个异步组件。在
AsyncComponent
加载过程中,用户会看到“Loading…”信息。一旦组件加载完成,
Suspense
将渲染该组件,替换掉加载提示。
高级场景
Suspense
也支持更复杂的使用场景,比如在组件内部进行异步数据获取。这通常通过组合式API中的
async setup()
函数实现。
<template>
<Suspense>
<template #default>
<div>{{ data }}</div>
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script>
import { defineComponent } from 'vue';
import { fetchData } from './api'; // 假设的API请求函数
export default defineComponent({
async setup() {
const data = await fetchData();
return { data };
}
});
</script>
在这个场景中,组件利用
async setup()
函数来获取数据。在数据未到达之前,用户将看到“Loading…”提示。
虽然Suspense和骨架屏都是提升加载体验的手段,但Suspense更多的是从组件和逻辑层面提供支持,而骨架屏更侧重于视觉和用户感知层面。在实际应用中,二者可以结合使用,即在Suspense的fallback插槽中使用骨架屏,提供更加丰富和直观的加载状态反馈,进一步提升用户体验。
版权归原作者 接着奏乐接着舞。 所有, 如有侵权,请联系我们删除。