Vue3.3 + 新增了defineOptions、defineModel等实用语法糖,而Pinia则是 Vue3 官方推荐的状态管理工具(替代 Vuex)。
一、Vue3.3 新特性:语法糖简化开发
Vue3.3 推出了多个语法糖,核心是减少模板代码、提升开发效率。
1. defineOptions:简化组件选项
在 Vue3 中,组件的name、inheritAttrs等选项需要单独写在export default中,defineOptions可以直接在<script setup>中定义这些选项。
用法示例:
vue
<script setup>
// 直接在setup中定义组件选项
defineOptions({
name: 'MyComponent', // 组件名(用于keep-alive等场景)
inheritAttrs: false // 禁止属性继承到根元素
})
</script>
替代的旧写法:
vue
<script setup>
// 旧写法:需要额外写export default
</script>
<script>
export default {
name: 'MyComponent',
inheritAttrs: false
}
</script>
2. defineModel:简化双向绑定(v-model)
在 Vue3 中,子组件实现v-model需要同时处理props和emit,defineModel可以一行代码实现双向绑定。
用法示例:
子组件(Input.vue):
vue
<script setup>
// 用defineModel定义双向绑定的属性
const modelValue = defineModel()
</script>
<template>
<!-- 直接绑定到输入框 -->
<input v-model="modelValue" />
</template>
父组件:
vue
<script setup>
import Input from './Input.vue'
import { ref } from 'vue'
const msg = ref('')
</script>
<template>
<!-- 直接使用v-model -->
<Input v-model="msg" />
<p>输入内容:{{ msg }}</p>
</template>
替代的旧写法:
vue
<!-- 子组件旧写法 -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
二、Pinia:Vue3 官方状态管理工具
Pinia 是 Vue3 官方推荐的状态管理库,相比 Vuex 更轻量、更简洁,原生支持 TypeScript,是 Vue3 项目的首选。
1. 什么是 Pinia?
Pinia 可以理解为Vuex 的升级版,核心特点:
- 无
Mutations:直接在Action中修改状态; - 更简洁的 API:仅需
defineStore定义仓库; - 原生支持 TS:类型提示更友好;
- 轻量:打包体积仅 1KB 左右。
2. 手动添加 Pinia 到 Vue 项目
步骤 1:安装 Pinia
bash
npm install pinia
步骤 2:在入口文件注册 Pinia
javascript
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia' // 引入Pinia
import App from './App.vue'
const app = createApp(App)
app.use(createPinia()) // 注册Pinia
app.mount('#app')
3. Pinia 的基本语法:defineStore
通过defineStore定义一个 "仓库(Store)",每个仓库管理一块全局状态。
示例:定义用户仓库(userStore)
javascript
// src/stores/user.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 第一个参数:仓库唯一标识;第二个参数:仓库配置
export const useUserStore = defineStore('user', () => {
// 1. 状态(对应Vuex的state)
const userInfo = ref(null)
const token = ref('')
// 2. 计算属性(对应Vuex的getters)
const isLogin = () => {
return !!token.value
}
// 3. 方法(对应Vuex的actions,支持异步)
const login = async (form) => {
// 模拟接口请求
const res = await new Promise(resolve => {
setTimeout(() => {
resolve({
userInfo: { name: '张三', age: 20 },
token: 'pinia_token_123'
})
}, 1000)
})
// 直接修改状态(无需Mutations)
userInfo.value = res.userInfo
token.value = res.token
}
const logout = () => {
userInfo.value = null
token.value = ''
}
// 返回需要暴露的状态、计算属性、方法
return { userInfo, token, isLogin, login, logout }
})
4. 在组件中使用 Pinia
在组件中通过useUserStore获取仓库实例,直接使用状态和方法。
vue
<script setup>
import { useUserStore } from '@/stores/user'
// 获取仓库实例
const userStore = useUserStore()
// 调用仓库方法
const handleLogin = async () => {
await userStore.login({ username: 'zhangsan', password: '123' })
}
</script>
<template>
<div v-if="userStore.isLogin()">
<p>用户名:{{ userStore.userInfo?.name }}</p>
<button @click="userStore.logout">退出登录</button>
</div>
<button v-else @click="handleLogin">登录</button>
</template>
5. Action 异步写法
Pinia 的Action支持异步操作(直接写async/await),无需像 Vuex 那样区分同步 / 异步。
javascript
// src/stores/article.js
export const useArticleStore = defineStore('article', () => {
const articleList = ref([])
// 异步Action:请求文章列表
const fetchArticleList = async () => {
const res = await fetch('https://api.example.com/article/list')
const data = await res.json()
articleList.value = data.list
}
return { articleList, fetchArticleList }
})
6. storeToRefs:解构响应式状态
直接解构 Pinia 仓库的状态会丢失响应式,storeToRefs可以保留响应式。
vue
<script setup>
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia' // 引入storeToRefs
const userStore = useUserStore()
// 解构响应式状态
const { userInfo, token } = storeToRefs(userStore)
// 方法直接解构(无需storeToRefs)
const { login, logout } = userStore
</script>
7. Pinia 持久化:状态本地存储
Pinia 默认不会持久化状态(刷新后丢失),可以用pinia-plugin-persistedstate插件实现本地存储。
步骤 1:安装插件
bash
npm install pinia-plugin-persistedstate
步骤 2:注册插件
javascript
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // 引入插件
import App from './App.vue'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) // 注册插件
createApp(App).use(pinia).mount('#app')
步骤 3:开启仓库持久化
javascript
// src/stores/user.js
export const useUserStore = defineStore('user', () => {
// ...状态和方法
}, {
persist: true // 开启持久化
})