Vue 3 Composition API简介
Vue 3引入了Composition API,这是对Options API的重大改进。Composition API提供了更灵活、更强大的代码组织方式,特别适合大型复杂应用。
基础使用
setup函数
import { ref, reactive, computed } from "vue";
export default {
setup() {
// 响应式数据
const count = ref(0);
const user = reactive({
name: "John",
age: 25
});
// 计算属性
const doubleCount = computed(() => count.value * 2);
// 方法
const increment = () => {
count.value++;
};
// 返回模板可用的数据和方法
return {
count,
user,
doubleCount,
increment
};
}
};
Script Setup语法糖
<script setup>
import { ref, reactive, computed } from "vue";
// 响应式数据
const count = ref(0);
const user = reactive({
name: "John",
age: 25
});
// 计算属性
const doubleCount = computed(() => count.value * 2);
// 方法
const increment = () => {
count.value++;
};
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
响应式系统
ref vs reactive
import { ref, reactive, isRef, unref } from "vue";
// ref - 用于基本类型和对象引用
const count = ref(0);
const userRef = ref({ name: "John" });
// reactive - 用于对象
const user = reactive({
name: "John",
age: 25,
address: {
city: "New York"
}
});
// 类型检查
console.log(isRef(count)); // true
console.log(isRef(user)); // false
// 解包ref
const rawValue = unref(count); // 0
响应式工具函数
import {
toRef,
toRefs,
isProxy,
isReactive,
isReadonly,
markRaw
} from "vue";
const user = reactive({
name: "John",
age: 25
});
// 将reactive属性转换为ref
const nameRef = toRef(user, "name");
// 解构reactive对象并保持响应性
const { name, age } = toRefs(user);
// 检查类型
console.log(isProxy(user)); // true
console.log(isReactive(user)); // true
console.log(isReadonly(user)); // false
// 标记为非响应式
const staticConfig = markRaw({
apiUrl: "https://api.example.com",
timeout: 5000
});
组合式函数
创建可复用的逻辑
// useCounter.js
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
const reset = () => {
count.value = initialValue;
};
return {
count,
increment,
decrement,
reset
};
}
// 在组件中使用
import { useCounter } from "./useCounter";
const { count, increment } = useCounter(10);
鼠标位置跟踪示例
// useMouse.js
import { ref, onMounted, onUnmounted } from "vue";
export function useMouse() {
const x = ref(0);
const y = ref(0);
const update = (event) => {
x.value = event.pageX;
y.value = event.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", update);
});
onUnmounted(() => {
window.removeEventListener("mousemove", update);
});
return { x, y };
}
// 在组件中使用
const { x, y } = useMouse();
生命周期钩子
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured
} from "vue";
export default {
setup() {
onBeforeMount(() => {
console.log("组件即将挂载");
});
onMounted(() => {
console.log("组件已挂载");
// 执行DOM操作或API调用
});
onBeforeUpdate(() => {
console.log("组件即将更新");
});
onUpdated(() => {
console.log("组件已更新");
});
onBeforeUnmount(() => {
console.log("组件即将卸载");
// 清理工作
});
onUnmounted(() => {
console.log("组件已卸载");
});
onErrorCaptured((error, instance, info) => {
console.error("捕获到错误:", error);
// 错误处理逻辑
return false; // 阻止错误继续向上传播
});
}
};
依赖注入
// 父组件提供数据
import { provide, ref } from "vue";
export default {
setup() {
const theme = ref("light");
const user = ref({ name: "John" });
// 提供数据给子组件
provide("theme", theme);
provide("user", user);
// 提供方法
provide("updateTheme", (newTheme) => {
theme.value = newTheme;
});
}
};
// 子组件注入数据
import { inject } from "vue";
export default {
setup() {
// 注入数据
const theme = inject("theme");
const user = inject("user");
const updateTheme = inject("updateTheme");
// 提供默认值
const config = inject("config", { timeout: 3000 });
// 工厂函数
const api = inject("api", () => {
return {
fetchData: () => { /* ... */ }
};
});
return {
theme,
user,
updateTheme,
config,
api
};
}
};
TypeScript支持
import { defineComponent, ref, Ref } from "vue";
interface User {
id: number;
name: string;
email: string;
}
interface CounterReturn {
count: Ref<number>;
increment: () => void;
reset: () => void;
}
// 类型安全的组合式函数
function useCounter(initialValue: number = 0): CounterReturn {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
const reset = () => {
count.value = initialValue;
};
return {
count,
increment,
reset
};
}
// 类型安全的组件
export default defineComponent({
name: "UserProfile",
props: {
userId: {
type: Number,
required: true
},
showEmail: {
type: Boolean,
default: false
}
},
setup(props) {
const user = ref<User | null>(null);
const loading = ref(false);
// 类型推断正常工作
const { count, increment } = useCounter();
const fetchUser = async () => {
loading.value = true;
try {
const response = await fetch(`/api/users/${props.userId}`);
user.value = await response.json();
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchUser();
});
return {
user,
loading,
count,
increment,
fetchUser
};
}
});
性能优化
响应式数据优化
import { shallowRef, shallowReactive, readonly } from "vue";
// shallowRef - 只对.value变化响应
const nestedObject = shallowRef({
deep: { value: 1 }
});
// 以下变化不会触发更新
nestedObject.value.deep.value = 2;
// 需要替换整个对象
nestedObject.value = { deep: { value: 2 } };
// shallowReactive - 只对根级属性响应
const shallowUser = shallowReactive({
name: "John",
address: { city: "NYC" }
});
// 以下变化会触发更新
shallowUser.name = "Jane";
// 以下变化不会触发更新
shallowUser.address.city = "LA";
// readonly - 创建只读代理
const protectedConfig = readonly({
apiUrl: "https://api.example.com"
});
// 尝试修改会触发警告
protectedConfig.apiUrl = "https://new.example.com"; // 警告!
计算属性缓存
import { computed, ref } from "vue";
const items = ref([
{ id: 1, name: "Item 1", price: 10 },
{ id: 2, name: "Item 2", price: 20 },
{ id: 3, name: "Item 3", price: 30 }
]);
// 缓存的计算属性
const totalPrice = computed(() => {
console.log("计算总价...");
return items.value.reduce((sum, item) => sum + item.price, 0);
});
// 多次访问只计算一次
console.log(totalPrice.value); // 计算总价... 60
console.log(totalPrice.value); // 60 (从缓存读取)
// 当依赖项变化时重新计算
items.value.push({ id: 4, name: "Item 4", price: 40 });
console.log(totalPrice.value); // 计算总价... 100
最佳实践
- 按功能组织代码:将相关逻辑放在同一个组合式函数中
- 合理使用ref和reactive:基本类型用ref,对象用reactive
- 利用TypeScript:为组合式函数和组件提供完整的类型定义
- 性能优化:在适当场景使用shallowRef、shallowReactive
- 错误处理:使用onErrorCaptured捕获和处理错误
- 代码复用:将通用逻辑提取为组合式函数
总结
Vue 3的Composition API为Vue应用开发带来了革命性的改进。通过更灵活的代码组织方式、更好的TypeScript支持和更强大的逻辑复用能力,Composition API使得构建大型复杂应用变得更加容易和高效。
关键要点:
- 使用setup函数或<script setup>语法糖
- 掌握ref和reactive的区别与使用场景
- 利用组合式函数实现逻辑复用
- 合理使用生命周期钩子和依赖注入
- 充分利用TypeScript的类型安全特性
通过实践这些概念和技巧,你将能够充分利用Composition API的优势,构建出更健壮、更可维护的Vue 3应用。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END




暂无评论内容