Vue3知识点
一、组合式 API(Composition API)核心
组合式 API 是 Vue3 最核心的特性,解决了 Vue2 选项式 API 中代码逻辑分散、大型组件难以维护的问题。所有代码都写在 <script setup> 语法糖中,更简洁高效。
1. ref:定义基础类型响应式数据
ref 用于定义字符串、数字、布尔值等基础数据类型或者对象类型的响应式变量,在 JS 中访问 / 修改需要加 .value,模板中直接使用。
案例:计数器
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="addCount">+1</button>
</div>
</template>
<script setup>
// 1. 导入 ref
import { ref } from 'vue'
// 2. 定义响应式数据
const count = ref(0)
// 3. 定义修改数据的方法
const addCount = () => {
// JS 中操作 ref 数据必须加 .value
count.value++
}
</script>
2. reactive:定义引用类型响应式数据
reactive 用于定义对象、数组等引用类型的响应式变量,无需加 .value,直接操作属性即可。
案例:用户信息展示与修改
<template>
<div>
<p>姓名:{{ user.name }}</p>
<p>年龄:{{ user.age }}</p>
<button @click="updateAge">修改年龄</button>
</div>
</template>
<script setup>
import { reactive } from 'vue'
// 定义响应式对象
const user = reactive({
name: 'Vue3初学者',
age: 20
})
// 修改对象属性
const updateAge = () => {
user.age++
}
</script>
3. computed:计算属性
依赖响应式数据自动计算新值,具有缓存特性,依赖数据不变时不会重复计算。
案例:总价计算
<template>
<div>
<p>单价:{{ price }} 元</p>
<p>数量:{{ num }}</p>
<p>总价:{{ totalPrice }} 元</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const price = ref(10)
const num = ref(2)
// 计算总价:依赖 price 和 num 自动更新
const totalPrice = computed(() => {
return price.value * num.value
})
</script>
4. watch:侦听器
监听响应式数据变化,数据改变时执行自定义逻辑(支持异步操作)。
案例:监听计数变化
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="count++">+1</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
// 监听 count 变化
watch(count, (newVal, oldVal) => {
console.log(`计数从 ${oldVal} 变为 ${newVal}`)
// 可执行异步请求、DOM 操作等
})
</script>
5. 生命周期函数
Vue3 组合式 API 中,生命周期以钩子函数形式使用,常用:
onMounted:组件挂载完成(DOM 渲染完毕,适合发请求、操作 DOM)onUpdated:组件更新完成onUnmounted:组件卸载(适合清除定时器、解绑事件)
案例:定时器 + 生命周期清理
<template>
<div>秒数:{{ timer }}</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const timer = ref(0)
let interval = null
// 组件挂载后开启定时器
onMounted(() => {
interval = setInterval(() => {
timer.value++
}, 1000)
})
// 组件卸载时清除定时器(防止内存泄漏)
onUnmounted(() => {
clearInterval(interval)
})
</script>
二、父子组件通信(defineProps + defineEmits)
组件化开发中,父传子用 defineProps ,子传父用 defineEmits,是 Vue3 组件通信的基础。
1. 父传子:defineprops 接收数据
子组件通过 defineProps 声明接收父组件传递的数据,支持类型校验。
父组件(Parent.vue)
<template>
<div>
<h3>父组件</h3>
<!-- 向子组件传递数据 -->
<Child :msg="parentMsg" :list="parentList" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const parentMsg = ref('我是父组件的数据')
const parentList = ref(['Vue3', 'Pinia', 'Vite'])
</script>
子组件(Child.vue)
<template>
<div>
<h4>子组件</h4>
<p>接收父组件消息:{{ msg }}</p>
<p>接收列表:{{ list }}</p>
</div>
</template>
<script setup>
// 子组件声明接收 props,自带类型校验
const props = defineProps({
msg: String,
list: Array
})
</script>
2. 子传父:defineEmits 触发事件
子组件通过 defineEmits 定义事件,触发事件向父组件传递数据;父组件监听事件接收数据。
子组件(Child.vue)
<template>
<button @click="sendToParent">向父组件传值</button>
</template>
<script setup>
// 1. 定义可触发的事件
const emit = defineEmits(['child-event'])
const sendToParent = () => {
// 2. 触发事件,传递数据
emit('child-event', '我是子组件传递的内容')
}
</script>
父组件(Parent.vue)
<template>
<Child @child-event="getChildData" />
<p>接收子组件数据:{{ childData }}</p>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childData = ref('')
// 接收子组件传递的数据
const getChildData = (val) => {
childData.value = val
}
</script>
三、Pinia:Vue3 官方状态管理库
Pinia 替代 Vuex 成为 Vue3 专属状态管理,语法更简洁、支持 TypeScript、无模块化嵌套,核心:defineStore 定义仓库,state 存数据,actions 改数据。
1. 安装 Pinia
运行
npm install pinia
2. 全局注册(main.js)
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia()) // 注册 Pinia
app.mount('#app')
3. 定义仓库(stores/counter.js)
// 1. 导入 defineStore
import { defineStore } from 'pinia'
// 2. 定义仓库:第一个参数是仓库唯一 ID
export const useCounterStore = defineStore('counter', {
// 状态数据(类似 data)
state: () => ({
count: 0
}),
// 修改状态的方法(类似 methods,支持异步)
actions: {
addCount() {
this.count++
},
reduceCount() {
this.count--
}
}
})
4. 组件使用 Pinia
<template>
<div>
<p>Pinia 计数:{{ counterStore.count }}</p>
<button @click="counterStore.addCount">+1</button>
<button @click="counterStore.reduceCount">-1</button>
</div>
</template>
<script setup>
// 导入仓库
import { useCounterStore } from '@/stores/counter'
// 实例化仓库
const counterStore = useCounterStore()
</script>
补充 1:Pinia Action 异步写法
Action 支持 async/await 处理异步逻辑(如接口请求),和普通函数用法一致,是项目中最常用的场景。
场景:请求用户列表并更新状态
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
userList: [],
loading: false
}),
actions: {
// 异步 Action,支持 async/await
async fetchUserList() {
this.loading = true
try {
// 模拟接口请求(实际项目替换为 axios 请求)
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await res.json()
this.userList = data
} catch (err) {
console.error('请求失败', err)
} finally {
this.loading = false
}
}
}
})
组件中使用
<template>
<div>
<button @click="userStore.fetchUserList" :disabled="userStore.loading">
{{ userStore.loading ? '加载中...' : '获取用户列表' }}
</button>
<ul>
<li v-for="user in userStore.userList" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
</script>
补充 2:Pinia storeToRefs 方法
直接解构 Pinia 仓库数据会丢失响应式,storeToRefs 可以安全地把仓库中的 state 和 getters 转为响应式变量,方便模板中直接使用。
错误写法(丢失响应式)
// 错误:解构后 count 不是响应式,页面不会自动更新
const counterStore = useCounterStore()
const { count } = counterStore
正确写法(使用 storeToRefs)
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="addCount">+1</button>
</div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
// 1. 使用 storeToRefs 解构 state/getters,保持响应式
const { count } = storeToRefs(counterStore)
// 2. actions 可以直接解构(不会丢失响应式)
const { addCount } = counterStore
</script>
补充 3:Pinia 数据持久化
Pinia 默认数据存在内存中,刷新页面会丢失。通过 pinia-plugin-persistedstate 插件可以实现数据持久化(存入 localStorage/sessionStorage)。
步骤 1:安装插件
运行
npm install pinia-plugin-persistedstate
步骤 2:全局注册插件(main.js)
js
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) // 注册持久化插件
const app = createApp(App)
app.use(pinia)
app.mount('#app')
步骤 3:在仓库中开启持久化
js
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
addCount() {
this.count++
}
},
// 开启持久化配置
persist: {
key: 'counter-key', // 存入 localStorage 的 key 名,不写默认用仓库 ID
storage: localStorage, // 可选:localStorage / sessionStorage
paths: ['count'] // 只持久化指定字段,不写则持久化全部 state
}
})
效果:修改 count 后刷新页面,数据不会丢失,会自动从 localStorage 中恢复。
更多推荐


所有评论(0)