Vue 3 无 return 的 Composition API 写法(使用 <script setup> 语法糖)
Vue 3.2+ 引入了 <script setup> 语法糖,可以让你在不使用 return 的情况下更简洁地编写 Composition API 代码。
基础示例
html
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">+1</button>
<p>Message: {{ message }}</p>
<input v-model="message">
</div>
</template>
<script setup>
import {ref} from 'vue'
// 声明的变量和函数自动暴露给模板
const count = ref(0)
const message = ref('Hello Vue 3')
function increment() {
count.value++
}
</script>生命周期钩子
html
<script setup>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
onBeforeMount(() => {
console.log('beforeMount')
})
onMounted(() => {
console.log('mounted')
})
onBeforeUpdate(() => {
console.log('beforeUpdate')
})
onUpdated(() => {
console.log('updated')
})
onBeforeUnmount(() => {
console.log('beforeUnmount')
})
onUnmounted(() => {
console.log('unmounted')
})
</script>计算属性和侦听器
html
<template>
<div>
<input v-model="firstName" placeholder="First name">
<input v-model="lastName" placeholder="Last name">
<p>Full name: {{ fullName }}</p>
<p>Question: {{ question }}</p>
<p>Answer: {{ answer }}</p>
</div>
</template>
<script setup>
import {ref, computed, watch} from 'vue'
const firstName = ref('')
const lastName = ref('')
const question = ref('')
const answer = ref('')
// 计算属性
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`.trim()
})
// 侦听器
watch(question, async (newQuestion) => {
if (newQuestion.includes('?')) {
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
const data = await res.json()
answer.value = data.answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
}
}
})
</script>组件通信
父组件
html
<template>
<ChildComponent
:title="parentTitle"
@child-event="handleChildEvent"
/>
</template>
<script setup>
import {ref} from 'vue'
import ChildComponent from './ChildComponent.vue'
const parentTitle = ref('Parent Title')
function handleChildEvent(payload) {
console.log('Received from child:', payload)
}
</script>子组件
html
<template>
<div>
<h2>{{ title }}</h2>
<button @click="sendToParent">Send to Parent</button>
</div>
</template>
<script setup>
// 定义 props
const props = defineProps({
title: {
type: String,
required: true
}
})
// 定义 emits
const emit = defineEmits(['child-event'])
function sendToParent() {
emit('child-event', {message: 'Hello from child!'})
}
</script>组合式函数复用
html
<script setup>
import {useMouse} from './mouse.js'
// 使用组合式函数
const {x, y} = useMouse()
</script>javascript
// mouse.js
import {ref, onMounted, onUnmounted} from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return {x, y}
}模板引用
html
<template>
<input ref="inputRef">
</template>
<script setup>
import {ref, onMounted} from 'vue'
// 声明模板引用
const inputRef = ref(null)
onMounted(() => {
inputRef.value.focus()
})
</script>TypeScript 支持
html
<script setup lang="ts">
// 带类型的 props
interface
Props
{
title: string
count ? : number
}
const props = defineProps < Props > ()
// 带类型的 emits
const emit = defineEmits < {
(e
:
'update:count', value
:
number
):
void
(e: 'reset')
:
void
}>
()
// 带类型的 ref
const count = ref < number > (0)
</script>特点总结
- 自动暴露:
<script setup>中声明的顶级变量、函数和导入内容自动暴露给模板 - 更简洁:无需手动
return所有需要暴露的内容 - 更好的 TypeScript 支持:类型推断更自然
- 性能更好:编译时转换,运行时开销更小
- 组合式函数更易用:可以像普通函数一样直接使用
注意:<script setup> 是一种编译时语法糖,最终会被编译为标准的 Composition API 代码。