在 Vue 3 中,setup
函数的写法有两种主要方式:一种是使用 <script setup>
标签,另一种是写在 export default
对象中作为 setup
函数。它们之间的区别如下:
-
<script setup>
标签-
位置:使用
<script setup>
标签来编写setup
函数。 -
作用:是 Vue 3 的 Composition API 的一种语法糖,简化了
setup
函数的使用。 -
优点:
- 简化语法: 省去了显式地定义
setup
函数,代码更简洁。 - 更好支持 TypeScript: 更好的类型推断和更简洁的 TypeScript 支持。
- 自动导入: 可以自动导入一些 Vue 内置的 API 和自定义的组件、函数等。
<template><div>{{ message }}</div> </template><script setup> import { ref } from 'vue';const message = ref('Hello Vue 3!'); </script>
- 简化语法: 省去了显式地定义
-
注意:此写法,
defineProps
和defineEmits
是自动使用,无需显式导入
-
-
export default
对象中的setup
函数-
位置:在
export default
对象中定义setup
函数。 -
作用:这种方式是 Vue 3 提供的标准方式,允许在对象中定义
setup
方法。 -
优点:
- 与 Options API 兼容: 适用于需要结合使用 Composition API 和 Options API 的情况。
- 传统方式: 适合于逐步迁移旧代码或与传统 Vue 2.x 的 Options API 结合使用。
<template><div>{{ message }}</div> </template><script> import { ref } from 'vue';export default {setup() {const message = ref('Hello Vue 3!');return { message };} } </script>
-
总结
<script setup>
: 更简洁、易读,适合新开发的 Vue 3 组件和更复杂的逻辑组织。export default
对象中的setup
: 更兼容旧有代码和 Options API,适合需要逐步迁移的项目。
声明变量
-
ref
-
适用场景:主要用于定义单一的基本类型(如字符串、数字、布尔值)或对非响应式对象的包装。它也适用于创建响应式的引用类型数据(浅层响应式)。
-
使用方法:创建一个包含
.value
属性的响应式对象,你需要通过.value
来访问和修改其值。 -
示例:
<template><div>{{ count }}</div><button @click="increment">Increment</button> </template><script setup> import { ref } from 'vue';// 创建一个响应式的基本类型变量 const count = ref(0);// 修改变量值 function increment() {count.value++; } </script>
-
-
reactive:
-
适用场景:用于创建一个深度响应式的对象。它主要用于处理复杂的数据结构,如嵌套对象和数组。
reactive
会对对象的所有嵌套属性进行响应式处理。 -
使用方法:使用
reactive
创建的对象本身就是响应式的,你可以直接访问和修改对象的属性,而不需要通过.value
。 -
示例:
<template><div>{{ user.name }}</div><button @click="updateName">Change Name</button> </template><script setup> import { reactive } from 'vue';// 创建一个响应式的对象 const user = reactive({name: 'John Doe' });// 修改对象属性 function updateName() {user.name = 'Jane Doe'; } </script>
-
计算属性
-
基本用法:用来进行数据的衍生计算。
<template><div><p>Count: {{ count }}</p><p>Doubled Count: {{ doubledCount }}</p><button @click="count++">Increment</button></div> </template><script> import { ref, computed } from 'vue';export default {setup() {const count = ref(0);// 定义计算属性const doubledCount = computed(() => count.value * 2);return {count,doubledCount};} }; </script>
-
特性:
-
响应式:计算属性会自动依赖其内部使用的数据,并且在这些数据发生变化时会重新计算。Vue 会智能地缓存计算属性的值,直到它的依赖数据发生变化。
-
只读:默认情况下,计算属性是只读的。如果你需要计算属性具有 setter(写入)功能,可以提供一个对象的形式来定义计算属性,如下所示:
import { ref, computed } from 'vue';export default {setup() {const count = ref(0);// 定义具有 getter 和 setter 的计算属性const doubledCount = computed({get: () => count.value * 2,set: (newValue) => {count.value = newValue / 2;}});return {count,doubledCount};} };
-
生命周期钩子函数
-
onBeforeMount
-
用途: 在组件挂载之前被调用。此钩子在模板编译完成但尚未挂载到 DOM 上时触发。
-
函数签名:
import { onBeforeMount } from 'vue';onBeforeMount(() => {console.log('Component is about to mount'); });
-
-
onMounted
-
用途: 在组件挂载到 DOM 后调用。用于访问 DOM 元素或执行需要在 DOM 渲染后才能完成的操作。
-
函数签名:
import { onMounted } from 'vue';onMounted(() => {console.log('Component has been mounted'); });
-
-
onBeforeUpdate
-
用途: 在组件更新之前被调用。此钩子在组件的数据发生变化并将要重新渲染时触发。
-
函数签名:
import { onBeforeUpdate } from 'vue';onBeforeUpdate(() => {console.log('Component is about to update'); });
-
-
onUpdated
-
用途: 在组件更新之后调用。用于处理更新后的逻辑或与新的 DOM 状态相关的操作。
-
函数签名:
import { onUpdated } from 'vue';onUpdated(() => {console.log('Component has been updated'); });
-
-
onBeforeUnmount
-
用途: 在组件卸载之前被调用。用于清理资源或移除事件监听器等操作。
-
函数签名:
import { onBeforeUnmount } from 'vue';onBeforeUnmount(() => {console.log('Component is about to unmount'); });
-
-
onUnmounted
-
用途: 在组件卸载后调用。用于执行卸载后需要完成的操作,如清理外部资源或停止定时器。
-
函数签名:
import { onUnmounted } from 'vue';onUnmounted(() => {console.log('Component has been unmounted'); });
-
-
onErrorCaptured
-
用途: 当组件的子组件发生错误时调用。可以用于捕获错误并处理它们。
-
函数签名:
import { onErrorCaptured } from 'vue';onErrorCaptured((error, instance, info) => {console.error('Error captured:', error);return false; // 如果返回 false,错误不会被进一步处理 });
-
-
onActivated
-
用途: 当组件被激活时调用。主要用于
<keep-alive>
包裹的组件,组件从缓存中激活时触发。 -
函数签名:
import { onActivated } from 'vue';onActivated(() => {console.log('Component has been activated'); });
-
-
onDeactivated
-
用途: 当组件被停用时调用。主要用于
<keep-alive>
包裹的组件,组件被缓存时触发。 -
函数签名:
import { onDeactivated } from 'vue';onDeactivated(() => {console.log('Component has been deactivated'); });
-
响应式属性监听
-
watch
-
作用:一个用于监听数据变化并执行回调函数的 API。可以用于监视响应式数据的变化、执行副作用操作或处理复杂的逻辑。提供了更灵活的方式来处理数据变化,与计算属性 (
computed
) 的响应性相比,watch
更适合处理需要副作用的场景。 -
基本用法:
-
允许你观察一个或多个响应式数据源,并在这些数据源发生变化时执行回调函数
import { ref, watch } from 'vue';export default {setup() {const count = ref(0);// 监视 `count` 的变化watch(count, (newValue, oldValue) => {console.log(`Count changed from ${oldValue} to ${newValue}`);});const info = reactive({name: 'dfc'});// 监视 `name` 的变化watch(() => info.name, (newName, oldName) => {console.log(`info.name changed from ${oldName} to ${newName}`);})return {count};} };
import { ref, watch, toRefs } from 'vue';export default {setup() {const count = ref(0);const name = ref('Alice');// 监视多个数据源watch([count, name], ([newCount, newName], [oldCount, oldName]) => {console.log(`Count changed from ${oldCount} to ${newCount}`);console.log(`Name changed from ${oldName} to ${newName}`);});const info = reactive({name: 'dfc',age: 12,});// 监视多个数据源watch([() => info.name, () => info.age], ([newName, oldName], [newAge, oldAge]) => {console.log(`info.name changed from ${oldName} to ${newName}`);console.log(`info.age changed from ${oldAge} to ${newAge}`);});return {count,name,info,// ...toRefs(info)};} };
-
-
其他特性:
-
深度监视:需要深度监视对象的嵌套属性,可以使用
deep
选项import { ref, watch } from 'vue';export default {setup() {const user = ref({ name: 'Alice', age: 30 });// 深度监视 `user` 对象watch(user, (newValue, oldValue) => {console.log('User object changed:', newValue);}, { deep: true });return {user};} };
-
立即执行:初始化时立即执行一次回调,可以使用
immediate
选项import { ref, watch } from 'vue';export default {setup() {const count = ref(0);// 立即执行回调watch(count, (newValue, oldValue) => {console.log(`Count changed from ${oldValue} to ${newValue}`);}, { immediate: true });return {count};} };
-
停止监听:需要在某些条件下停止监听,可以使用
watch
函数返回的停止函数import { ref, watch } from 'vue';export default {setup() {const count = ref(0);const stopWatch = watch(count, (newValue, oldValue) => {console.log(`Count changed from ${oldValue} to ${newValue}`);});// 停止监听setTimeout(() => {stopWatch();console.log('Stopped watching count');}, 5000);return {count};} };
-
-
-
watchEffect
-
作用:一个用于自动追踪响应式数据并执行副作用的 API。它与
watch
不同,因为watchEffect
不需要明确地指定要观察的数据源,而是自动追踪函数内部使用的所有响应式数据。这使得watchEffect
更加简洁和直观,特别是当你不需要对数据变化做复杂的处理时。 -
基本用法:
import { ref, watchEffect } from 'vue';export default {setup() {const count = ref(0);// 使用 watchEffect 追踪 count 的变化watchEffect(() => {console.log(`Count is: ${count.value}`);});// 修改 count 的值setTimeout(() => {count.value = 1;}, 1000);return {count};} };
-
处理副作用:
watchEffect
主要用于处理副作用,如更新 DOM、发送网络请求等。它在数据源变化时会重新执行回调函数,因此非常适合处理那些与数据变化有关的操作。 -
停止追踪
import { ref, watchEffect } from 'vue';export default {setup() {const count = ref(0);// 使用 watchEffect 追踪 count 的变化const stop = watchEffect(() => {console.log(`Count is: ${count.value}`);});// 停止追踪setTimeout(() => {stop();console.log('Stopped watching count');}, 5000);return {count};} };
-
与
watch
的对比watchEffect
和watch
都可以用来处理响应式数据的变化,但它们的使用场景和方式有所不同:watchEffect
: 自动追踪函数内所有响应式数据的变化,适合处理简单的副作用,不需要手动指定数据源。watch
: 需要明确指定要观察的数据源,适合处理更复杂的逻辑和副作用,允许对数据源变化进行更细粒度的控制。
-
深度追踪
import { ref, watch } from 'vue';export default {setup() {const user = ref({ name: 'Alice', age: 30 });// 使用 watch 进行深度追踪watch(user, (newValue, oldValue) => {console.log('User object changed:', newValue);}, { deep: true });return {user};} };
-
内置组件
-
Teleport
-
作用:允许你将子组件的渲染内容“传送”到 DOM 中的不同位置
-
示例:
// teleport 将模态框渲染到 body 元素中,而不是其父组件的 DOM 结构中 <template><div><button @click="showModal = !showModal">Toggle Modal</button><teleport to="body"><div v-if="showModal" class="modal"><p>This is a modal!</p><button @click="showModal = false">Close</button></div></teleport></div> </template><script> import { ref } from 'vue';export default {setup() {const showModal = ref(false);return {showModal};} }; </script><style> .modal {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.5);display: flex;align-items: center;justify-content: center; } </style>
-
-
Suspense
-
作用:用于处理异步组件的加载过程,它可以在组件异步加载时显示一个加载状态。这个功能非常适合在渲染异步数据或组件时提供用户反馈。
-
示例:
// Suspense 组件会在 AsyncComponent 加载时显示一个“Loading...”的文本,直到异步组件加载完成。 <template><suspense><template #default><AsyncComponent /></template><template #fallback><p>Loading...</p></template></suspense> </template><script> import { defineAsyncComponent } from 'vue';const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue'));export default {components: {AsyncComponent} }; </script>
-
-
Fragment
-
作用:支持多个根节点的功能,它允许一个组件返回多个根元素,而不需要额外的包裹元素。这个功能可以简化组件结构,避免不必要的 DOM 节点。
-
示例:
<template><div></div><p>First element</p><p>Second element</p> </template><script> export default {setup() {return {};} }; </script>
在Vue3中使用Fragment只需要在模板中使用
template
标签包裹多个根节点即可。
-
组件通信
组件通信
异步组件
-
defineAsyncComponent
-
作用:用于定义异步组件的函数,允许你动态地加载组件,通常用于按需加载,以提高应用的性能和响应速度。
-
示例:
// 定义一个异步组件 AsyncComponent,它会在组件需要被渲染时才会被动态加载。import { defineAsyncComponent } from 'vue';const AsyncComponent = defineAsyncComponent(() =>import('./MyAsyncComponent.vue') );export default {components: {AsyncComponent} };
-
配置选项:
选项 是否必填 含义 loader 是 返回一个 Promise,Promise 解析为异步组件 loadingComponent 否 指定一个加载中组件,在异步组件正在加载时显示 errorComponent 否 指定一个错误组件,如果异步组件加载失败时显示 delay 否 指定加载组件的延迟时间(以毫秒为单位) timeout 否 指定加载组件的超时时间(以毫秒为单位) -
完整示例:
// AsyncComponent 将在加载时显示一个“Loading...”组件,如果加载失败,则显示一个错误组件。如果异步组件的加载超过了 10 秒,则会显示错误组件。import { defineAsyncComponent } from 'vue';// 定义异步组件,带有加载、错误处理和延迟配置 const AsyncComponent = defineAsyncComponent({loader: () => import('./MyAsyncComponent.vue'),loadingComponent: {template: '<div>Loading...</div>'},errorComponent: {template: '<div>Error loading component</div>'},delay: 200, // 200ms 延迟显示 loadingComponenttimeout: 10000 // 10秒超时 });export default {components: {AsyncComponent} };
-
Vueuse(工具函数)
-
介绍:用于 Vue 3 的工具库,提供了一系列有用的 Composition API 组合函数,帮助开发者更高效地处理常见任务。它通过简化状态管理、响应式数据和副作用的处理,提高了开发效率。
-
主要功能:
- 状态管理:如
useLocalStorage
和useSessionStorage
让状态在浏览器存储中持久化。 - 副作用:如
useFetch
用于进行 HTTP 请求,useInterval
和useTimeout
用于定时任务。 - 事件处理:如
useEventListener
用于添加和移除事件监听器。 - 响应式数据:如
useDark
处理暗黑模式,useMouse
跟踪鼠标位置。
- 状态管理:如
-
安装与使用
-
安装
npm install @vueuse/core
-
使用
// 使用 useLocalStorage 管理本地存储:<template><input v-model="name" placeholder="Enter your name" /> </template><script lang="ts"> import { useLocalStorage } from '@vueuse/core';export default {setup() {const name = useLocalStorage('name', '');return { name };} }; </script>
-