vue<script setup>import { ref, reactive } from 'vue'
// 基本类型数据(推荐 ref)
const count = ref(0)
// 对象类型数据(推荐 reactive)
const user = reactive({
name: 'Alice',
age: 25,
profile: {
email: 'alice@example.com'
}
})
// 修改数据
const increment = () => {
count.value++ // 注意 ref 需要 .value
user.age += 1
user.profile.email = 'new@example.com'
}
</script>
<template>
<!-- 基本类型渲染 -->
<p>Count: {{ count }}</p>
<!-- 对象属性渲染 -->
<p>Name: {{ user.name }}</p>
<p>Email: {{ user.profile.email }}</p>
<!-- 方法绑定 -->
<button @click="increment">Increase</button>
</template>
vue<script setup>import { reactive, toRefs } from 'vue'
const state = reactive({
firstName: 'John',
lastName: 'Doe'
})
// 使用 toRefs 解构保持响应性
const { firstName, lastName } = toRefs(state)
const changeName = () => {
state.firstName = 'Jane' // 原始对象修改
lastName.value = 'Smith' // 解构后的 ref 修改
}
</script>
<template>
<p>{{ firstName }} {{ lastName }}</p>
</template>
vue<script setup>import { reactive } from 'vue'
const list = reactive([
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' }
])
const addItem = () => {
// 正确方式:触发响应式更新
list.push({ id: Date.now(), text: `Item ${list.length + 1}` })
}
const removeItem = (id) => {
const index = list.findIndex(item => item.id === id)
if (index > -1) {
list.splice(index, 1)
}
}
</script>
<template>
<ul>
<li v-for="item in list" :key="item.id">
{{ item.text }}
<button @click="removeItem(item.id)">×</button>
</li>
</ul>
<button @click="addItem">Add Item</button>
</template>
vue<template> <!-- v-if / v-else -->
<div v-if="count > 5">超过5次点击</div>
<div v-else>继续点击</div>
<!-- v-show -->
<div v-show="isVisible">显示/隐藏内容</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const isVisible = ref(true)
</script>
vue<template> <!-- 带索引的遍历 -->
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index + 1 }}. {{ item.name }}
</li>
</ul>
<!-- 遍历对象 -->
<div v-for="(value, key) in obj" :key="key">
{{ key }}: {{ value }}
</div>
</template>
<script setup>
import { reactive } from 'vue'
const items = reactive([
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' }
])
const obj = reactive({
title: 'Vue 3 Guide',
author: 'John Doe'
})
</script>
vue<script setup>import { reactive, computed } from 'vue'
const cart = reactive({
items: [
{ name: 'Book', price: 20, quantity: 2 },
{ name: 'Pen', price: 5, quantity: 5 }
]
})
// 计算总价
const total = computed(() => {
return cart.items.reduce((sum, item) =>
sum + item.price * item.quantity, 0
)
})
</script>
<template>
<p>Total: {{ total }}</p>
</template>
vue<script setup>import { ref, watch } from 'vue'
const searchQuery = ref('')
const results = ref([])
// 侦听搜索词变化
watch(searchQuery, async (newVal) => {
if (newVal.length < 2) return
results.value = await fetchResults(newVal)
}, { immediate: true })
// 深度侦听对象
const user = reactive({ name: 'Alice' })
watch(
() => ({ ...user }), // 深度克隆对象
(newVal, oldVal) => {
console.log('User changed:', newVal)
},
{ deep: true }
)
</script>
响应式数据规范
基本类型用 ref
复杂对象用 reactive
需要解构时使用 toRefs
列表渲染优化
vue<!-- 好的做法 --><div v-for="item in list" :key="item.id"> <!-- 避免使用索引作为 key --> <div v-for="(item, index) in list" :key="index"> <!-- 不推荐 -->
减少不必要的响应式
javascript// 不需要响应式的数据const staticData = { MAX_ITEMS: 100 // 使用普通对象}
大型数据优化
javascript// 使用 shallowRef/shallowReactiveimport { shallowRef } from 'vue'const bigList = shallowRef([]) // 只跟踪根层级变化
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 数据定义 | data() 返回对象 | ref()/reactive() 函数 |
| 数组更新检测 | 需要 Vue.set | 原生数组方法自动响应 |
| 响应式原理 | Object.defineProperty | Proxy |
| 类型支持 | 有限 | 完整的 TypeScript 支持 |
| 代码组织 | Options API | Composition API |
响应式丢失问题
javascript// 错误方式const { x, y } = reactive({ x: 1, y: 2 }) // 失去响应性// 正确方式const pos = reactive({ x: 1, y: 2 })const { x, y } = toRefs(pos)异步更新队列
javascriptimport { nextTick } from 'vue'const updateData = async () => { count.value++ await nextTick() console.log('DOM updated')}跨组件数据传递
javascript// 使用 provide/injectimport { provide, ref } from 'vue'const globalData = ref({})provide('appData', globalData)通过以上模式,您可以高效地在 Vue 3 组件中管理数据和实现视图渲染。组合式 API 的灵活性能让复杂组件的逻辑更易于组织和复用。