在 Vue 3 中,setup()
是 Composition API 的核心入口,它提供了更灵活、可复用和模块化的代码组织方式。
一、setup()
高阶使用技巧
1. 使用 defineProps
和 defineEmits
(无需导入)
Vue 3.3+ 支持自动推导 props 和 emits,无需手动引入函数。
<script setup>
const props = defineProps(['title', 'content']);
const emit = defineEmits(['update:title', 'submit']);
function handleSubmit() {
emit('submit', { data: props.content });
}
</script>
2. 结合 TypeScript 类型推导
提升类型安全性,支持自动补全和类型检查。
interface User {
id: number;
name: string;
age?: number;
}
const props = defineProps<{
user: User;
isActive: boolean;
}>();
3. 自定义逻辑封装为组合函数(Composable)
将可复用逻辑提取到独立函数中,便于跨组件复用。
// useUserValidation.ts
import { ref } from 'vue';
export function useUserValidation(user) {
const isValid = ref(false);
function validate() {
isValid.value = !!user.name && user.age > 0;
}
return { isValid, validate };
}
在组件中使用:
<script setup>
import { useUserValidation } from '@/composables/useUserValidation';
const props = defineProps(['user']);
const { isValid, validate } = useUserValidation(props.user);
</script>
4. 使用 ref
和 reactive
控制响应性粒度
- 使用
ref
管理基础类型。 - 使用
reactive
管理对象/数组。 - 对不需要响应式的数据使用
markRaw()
或普通变量。
import { markRaw } from 'vue';
const largeData = markRaw(JSON.parse(localStorage.getItem('bigData')));
二、性能优化策略
1. 避免不必要的响应式数据
- 对静态或大数据量对象使用
markRaw()
,防止 Vue 自动将其转换为响应式对象。
const config = markRaw({ theme: 'dark', version: '1.0.0' });
2. 控制副作用生命周期
- 使用
onBeforeUnmount
清理副作用(如定时器、事件监听器)。 - 使用
effectScope
管理多个响应式依赖的生命周期。
import { effectScope, onBeforeUnmount } from 'vue';
const scope = effectScope();
scope.run(() => {
const count = ref(0);
watchEffect(() => {
console.log(count.value);
});
onBeforeUnmount(() => {
scope.stop(); // 手动清理所有副作用
});
});
3. 避免重复计算与渲染
- 使用
computed
缓存计算结果。 - 使用
v-once
或<keep-alive>
缓存静态内容。 - 使用
key
控制组件重新渲染时机。
<template>
<div :key="user.id">
<!-- 当 user.id 变化时才会重新渲染 -->
{{ computedName }}
</div>
</template>
4. 减少模板中的复杂逻辑
- 模板中应尽量只调用简单变量或
computed
,避免直接写复杂表达式。 - 将复杂逻辑封装到
methods
或 Composable 函数中。
三、开发与维护建议
1. 结构清晰、职责单一
- 每个组件只做一件事。
- 抽离通用逻辑到
composables/
目录下。
2. 良好的命名规范
- 组合函数命名以
useXxx
开头(如useAuth
,useFetch
)。 - 文件名使用大写驼峰命名法(如
UserProfile.vue
)。
3. 使用 Suspense
处理异步加载状态
- 结合异步组件实现优雅加载体验。
<template>
<Suspense>
<AsyncComponent />
<template #fallback>
加载中...
</template>
</Suspense>
</template>
4. 使用 Devtools 调试
- 利用 Vue Devtools 查看组件树、响应式依赖、性能面板等信息。
- 使用
console.warn()
或error
提醒潜在问题。
四、完整示例:高性能封装组件
<template>
<div class="data-table">
<table>
<thead>
<tr v-for="header in headers" :key="header.key">
<th>{{ header.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key="row.id">
<td v-for="col in headers" :key="col.key">{{ row[col.key] }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { fetchData } from '@/api/data';
const props = defineProps({
headers: {
type: Array,
required: true
}
});
const data = ref([]);
const loading = ref(false);
async function loadData() {
loading.value = true;
try {
const result = await fetchData();
data.value = result;
} finally {
loading.value = false;
}
}
onMounted(loadData);
const rows = computed(() => {
return data.value.map(item => ({
...item,
fullName: `${item.firstName} ${item.lastName}`
}));
});
</script>