Vue 3 script setup 语法糖:提升开发效率的利器
大家好,今天我们来深入探讨 Vue 3 中 script setup 语法糖,它如何帮助我们提升开发效率。script setup 是 Vue 3 引入的一种更简洁、更高效的组件编写方式,它将模板与逻辑代码更紧密地结合在一起,减少了冗余代码,提高了代码的可读性和可维护性。
什么是 script setup?
在 Vue 2 中,我们通常使用 options API 来定义组件,需要分别定义 data、methods、computed 等选项。这种方式虽然清晰,但在大型组件中,代码会变得分散,不易维护。
script setup 是 Vue 3 中 Composition API 的一种语法糖,它允许我们在一个 <script setup> 标签内编写组件的所有逻辑,而无需显式地使用 return 来暴露变量和方法给模板。编译器会自动处理这些细节,让代码更加简洁。
基本结构:
<template>
<div>
<h1>{{ message }}</h1>
<button @click="handleClick">Click me</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('Hello, Vue 3!')
function handleClick() {
message.value = 'Button clicked!'
}
</script>
在这个例子中,message 和 handleClick 自动暴露给模板,无需 return。
script setup 的优势
- 更简洁的代码: 减少了冗余的代码,例如
data、methods、computed等选项的定义。 - 更好的可读性: 将组件的逻辑代码集中在一起,更容易理解组件的功能。
- 更好的类型推断: 与 TypeScript 配合使用时,可以获得更好的类型推断,减少错误。
- 更好的性能: 编译器可以进行更多的优化,提高组件的性能。
如何使用 script setup
-
启用
script setup:
在你的 Vue 组件中使用<script setup>标签。 -
定义响应式状态:
使用ref或reactive来创建响应式状态。<script setup> import { ref, reactive } from 'vue' const count = ref(0) const user = reactive({ name: 'John Doe', age: 30 }) </script> -
定义方法:
直接在<script setup>中定义方法。<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } </script> -
使用计算属性:
使用computed来创建计算属性。<script setup> import { ref, computed } from 'vue' const count = ref(0) const doubleCount = computed(() => count.value * 2) </script> -
注册组件:
如果使用了其他组件,可以直接引入并使用,无需显式注册。<template> <div> <MyComponent /> </div> </template> <script setup> import MyComponent from './MyComponent.vue' </script> -
使用生命周期钩子:
使用onMounted、onUpdated、onUnmounted等生命周期钩子。<script setup> import { onMounted } from 'vue' onMounted(() => { console.log('Component mounted!') }) </script> -
定义 props:
使用defineProps宏来定义 props。<script setup> const props = defineProps({ message: { type: String, required: true } }) </script> <template> <div>{{ message }}</div> </template> -
定义 emits:
使用defineEmits宏来定义 emits。<script setup> const emit = defineEmits(['update']) function handleClick() { emit('update', 'new value') } </script> <template> <button @click="handleClick">Update</button> </template> -
暴露变量和方法 (显式暴露):
如果需要显式地暴露一些变量或方法给父组件,可以使用defineExpose宏。<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } defineExpose({ count, increment }) </script> -
使用
await获取顶层数据
可以在<script setup>中使用await直接获取数据,不需要额外的async setup()。Vue 会自动处理异步逻辑。<script setup> import { ref, onMounted } from 'vue' const data = ref(null) onMounted(async () => { const response = await fetch('https://api.example.com/data') data.value = await response.json() }) </script> <template> <div> <p v-if="data">Data: {{ data }}</p> <p v-else>Loading...</p> </div> </template>
示例:一个简单的计数器组件
使用 options API (Vue 2):
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
</script>
使用 script setup (Vue 3):
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
可以看到,使用 script setup 的代码更加简洁,易于阅读。
defineProps 和 defineEmits 的高级用法
-
类型声明: 可以使用 TypeScript 来定义 props 和 emits 的类型,提供更好的类型安全。
<script setup lang="ts"> interface Props { message: string; count?: number; // 可选属性 } const props = defineProps<Props>(); interface Emits { (e: 'update', value: string): void; (e: 'delete'): void; // 没有参数的事件 } const emit = defineEmits<Emits>(); function handleClick() { emit('update', 'new value'); } </script> -
使用对象语法: 也可以使用对象语法来定义 props 和 emits,提供更详细的配置。
<script setup> const props = defineProps({ message: { type: String, required: true }, count: { type: Number, default: 0 } }) const emit = defineEmits({ update: (value) => { // 验证 value 是否为字符串 return typeof value === 'string' } }) function handleClick() { emit('update', 'new value') } </script>
与 TypeScript 集成
script setup 与 TypeScript 配合使用可以提供更好的类型检查和代码提示,提高开发效率。
<template>
<div>
<h1>{{ message }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const message: string = 'Hello, TypeScript!'
const count = ref<number>(0)
function increment(): void {
count.value++
}
</script>
在这个例子中,我们使用了 TypeScript 来声明 message 的类型为 string,count 的类型为 number,increment 函数的返回值为 void。
在 script setup 中使用 use 引入composable函数
script setup 允许你直接引入和使用 composable 函数,进一步提高代码的复用性。
// useCounter.js (composable 函数)
import { ref } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
return {
count,
increment,
decrement
};
}
// MyComponent.vue
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script setup>
import { useCounter } from './useCounter';
const { count, increment, decrement } = useCounter(10); // 使用 initialValue = 10
</script>
使用 Suspense 组件配合 script setup 提升用户体验
当组件需要异步加载数据时,可以使用 Suspense 组件来提供一个友好的加载状态,配合 script setup 可以让代码更简洁。
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script setup>
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() => import('./components/AsyncComponent.vue'));
</script>
// AsyncComponent.vue
<template>
<div>
<p>Data: {{ data }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const data = ref(null);
onMounted(async () => {
// 模拟异步加载数据
await new Promise(resolve => setTimeout(resolve, 2000));
data.value = 'Async data loaded!';
});
</script>
在这个例子中,AsyncComponent 是一个异步组件,使用 Suspense 组件包裹,当 AsyncComponent 正在加载时,显示 "Loading…",加载完成后显示 AsyncComponent 的内容。
script setup 的一些注意事项
- 无法使用
this: 在script setup中无法使用this关键字,因为它是编译时语法糖,没有组件实例的概念。如果需要访问组件实例,可以使用getCurrentInstance。 - 命名冲突: 避免在
script setup中定义与 props 或 emits 同名的变量,以免发生命名冲突。 - 顶层声明:
script setup中的所有顶层声明都会自动暴露给模板,因此需要注意变量的作用域,避免污染全局作用域。
总结:更简洁,更高效的Vue组件开发方式
script setup 语法糖是 Vue 3 中一个强大的特性,它可以显著提高开发效率,让代码更简洁、易读、易维护。通过掌握 script setup 的基本用法和高级技巧,我们可以更好地利用 Vue 3 的 Composition API,构建更高效、更健壮的 Vue 应用。