Skip to content

setup 语法糖

setup 语法糖是Vue3.2+中引入的一个重要特性,它允许你在 <script setup> 标签中直接使用组合式API,而不需要返回变量和函数。本章节将详细介绍Vue3中setup语法糖的使用方法和最佳实践。

什么是 setup 语法糖?

setup 语法糖是Vue3.2+中对组合式API的一种简化写法,它允许你在 <script setup> 标签中直接定义变量和函数,这些变量和函数会自动暴露给模板使用,不需要在 setup() 函数中返回。

setup 语法糖的基本使用

1. 基本语法

vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
    <button @click="increment">Increment</button>
    <p>Count: {{ count }}</p>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const title = ref('Hello Vue3!')
const message = ref('Welcome to Vue3')
const count = ref(0)

const increment = () => {
  count.value++
}

onMounted(() => {
  console.log('Component mounted')
})
</script>

2. 与传统 setup 函数的对比

传统 setup 函数

vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const title = ref('Hello Vue3!')
    const message = ref('Welcome to Vue3')
    
    return {
      title,
      message
    }
  }
}
</script>

setup 语法糖

vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const title = ref('Hello Vue3!')
const message = ref('Welcome to Vue3')
</script>

setup 语法糖的优势

1. 代码更简洁

setup 语法糖避免了在 setup() 函数中返回变量和函数的繁琐写法,使代码更加简洁。

2. 自动暴露变量和函数

<script setup> 标签中定义的变量和函数会自动暴露给模板使用,不需要手动返回。

3. 更好的类型推导

setup 语法糖提供了更好的TypeScript支持,类型推导更加准确。

4. 更好的代码组织

setup 语法糖允许你按功能组织代码,使代码更加清晰。

setup 语法糖的核心特性

1. 导入组件

<script setup> 标签中,你可以直接导入并使用组件,不需要注册:

vue
<template>
  <div>
    <HelloWorld />
  </div>
</template>

<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>

2. 定义 props

<script setup> 标签中,你可以使用 defineProps 函数来定义组件的props:

vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
defineProps({
  title: {
    type: String,
    required: true
  },
  message: {
    type: String,
    default: 'Welcome to Vue3'
  }
})
</script>

3. 定义 emit

<script setup> 标签中,你可以使用 defineEmits 函数来定义组件的emit事件:

vue
<template>
  <div>
    <button @click="handleClick">Click me</button>
  </div>
</template>

<script setup>
const emit = defineEmits(['click'])

const handleClick = () => {
  emit('click')
}
</script>

4. 定义 expose

<script setup> 标签中,你可以使用 defineExpose 函数来暴露组件的属性和方法:

vue
<template>
  <div>
    <p>Count: {{ count }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)
const increment = () => {
  count.value++
}

defineExpose({
  count,
  increment
})
</script>

5. 使用 ref

<script setup> 标签中,你可以使用 ref 来创建响应式数据:

vue
<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

const increment = () => {
  count.value++
}
</script>

6. 使用 reactive

<script setup> 标签中,你可以使用 reactive 来创建响应式对象:

vue
<template>
  <div>
    <p>Name: {{ user.name }}</p>
    <p>Age: {{ user.age }}</p>
    <button @click="user.age++">Increment Age</button>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const user = reactive({
  name: 'John',
  age: 25
})
</script>

7. 使用 computed

<script setup> 标签中,你可以使用 computed 来创建计算属性:

vue
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <button @click="count++">Increment</button>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const count = ref(0)
const doubleCount = computed(() => count.value * 2)
</script>

8. 使用 watch

<script setup> 标签中,你可以使用 watch 来监听数据变化:

vue
<template>
  <div>
    <input v-model="message" type="text">
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

const message = ref('Hello')

watch(message, (newValue, oldValue) => {
  console.log(`Message changed from ${oldValue} to ${newValue}`)
})
</script>

9. 使用生命周期钩子

<script setup> 标签中,你可以使用生命周期钩子:

vue
<template>
  <div>
    <h1>Component</h1>
  </div>
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  console.log('Component mounted')
})

onUnmounted(() => {
  console.log('Component unmounted')
})
</script>

setup 语法糖的使用场景

1. 简单组件

对于简单的组件,setup语法糖可以使代码更加简洁:

vue
<template>
  <div class="button">
    <button :class="{ 'btn-primary': type === 'primary' }" @click="handleClick">
      {{ text }}
    </button>
  </div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
  text: {
    type: String,
    default: 'Button'
  },
  type: {
    type: String,
    default: 'primary'
  }
})

const emit = defineEmits(['click'])

const handleClick = () => {
  emit('click')
}
</script>

<style scoped>
.button {
  display: inline-block;
}

button {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.btn-primary {
  background-color: #42b983;
  color: white;
}
</style>

2. 复杂组件

对于复杂的组件,setup语法糖可以使代码更加清晰:

vue
<template>
  <div class="user-profile">
    <h1>{{ user.name }}</h1>
    <p>{{ user.email }}</p>
    <button @click="fetchUser">Refresh User</button>
    <div v-if="loading">Loading...</div>
    <div v-else-if="error">{{ error }}</div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const user = ref({})
const loading = ref(false)
const error = ref('')

const fetchUser = async () => {
  loading.value = true
  error.value = ''
  try {
    const response = await fetch('https://api.example.com/user')
    if (!response.ok) {
      throw new Error('Failed to fetch user')
    }
    const data = await response.json()
    user.value = data
  } catch (err) {
    error.value = err.message
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  fetchUser()
})
</script>

3. 可复用逻辑

对于可复用的逻辑,setup语法糖可以使代码更加简洁:

javascript
// composables/useCounter.js
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  const doubleCount = computed(() => count.value * 2)
  
  const increment = () => {
    count.value++
  }
  
  const decrement = () => {
    count.value--
  }
  
  return {
    count,
    doubleCount,
    increment,
    decrement
  }
}

然后在组件中使用:

vue
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script setup>
import { useCounter } from '../composables/useCounter'

const { count, doubleCount, increment, decrement } = useCounter(0)
</script>

setup 语法糖的最佳实践

1. 按功能组织代码

使用setup语法糖时,应该按功能组织代码,将相关的逻辑放在一起:

javascript
// 好的做法:按功能组织代码
const user = ref({})
const loading = ref(false)
const error = ref('')

const fetchUser = async () => {
  // 逻辑代码
}

onMounted(() => {
  fetchUser()
})

// 不好的做法:按API类型组织代码
const user = ref({})
const loading = ref(false)
const error = ref('')

onMounted(() => {
  fetchUser()
})

const fetchUser = async () => {
  // 逻辑代码
}

2. 合理使用响应式 API

根据数据类型选择合适的响应式API:

  • ref:用于基本类型数据
  • reactive:用于对象或数组
  • computed:用于计算属性
  • watch:用于监听数据变化

3. 避免在模板中使用复杂表达式

模板中的表达式应该简单明了,复杂逻辑应该放在setup语法糖中:

vue
<!-- 好的做法 -->
<template>
  <div>
    <p>{{ formattedPrice }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const price = ref(199.99)
const formattedPrice = computed(() => {
  return `$${price.value.toFixed(2)}`
})
</script>

<!-- 不好的做法 -->
<template>
  <div>
    <p>{{ `$${price.toFixed(2)}` }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const price = ref(199.99)
</script>

4. 合理使用 props 和 emit

使用 definePropsdefineEmits 来定义组件的props和emit事件:

vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <button @click="handleClick">Click me</button>
  </div>
</template>

<script setup>
const props = defineProps({
  title: {
    type: String,
    required: true
  }
})

const emit = defineEmits(['click'])

const handleClick = () => {
  emit('click')
}
</script>

5. 合理使用 expose

使用 defineExpose 来暴露组件的属性和方法:

vue
<template>
  <div>
    <p>Count: {{ count }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)
const increment = () => {
  count.value++
}

defineExpose({
  count,
  increment
})
</script>

总结

setup语法糖是Vue3.2+中一个重要的特性,它允许你在 <script setup> 标签中直接使用组合式API,而不需要返回变量和函数。通过setup语法糖,你可以创建更加简洁、清晰的组件。

在使用setup语法糖时,你应该按功能组织代码,合理使用响应式API,避免在模板中使用复杂表达式,以及合理使用props、emit和expose。

在后续的章节中,我们将学习Vue3的响应式API,包括ref、reactive、computed、watch等内容。

© 2026 编程马·菜鸟教程 版权所有