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 应用。