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 的灵活性能让复杂组件的逻辑更易于组织和复用。