Vue3 进阶,新特性 defineOptions/defineModel+Pinia 状态管理全解析

Vue3.3 + 新增了defineOptionsdefineModel等实用语法糖,而Pinia则是 Vue3 官方推荐的状态管理工具(替代 Vuex)。

一、Vue3.3 新特性:语法糖简化开发

Vue3.3 推出了多个语法糖,核心是减少模板代码、提升开发效率。

1. defineOptions:简化组件选项

在 Vue3 中,组件的nameinheritAttrs等选项需要单独写在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需要同时处理propsemitdefineModel可以一行代码实现双向绑定。

用法示例:

子组件(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 // 开启持久化
})

三、注意

想要了解更多有关Pinia的请点击这个链接到官网学习
想要学习持久化插件的更多内容的请点击这个链接

相关推荐
90后的晨仔2 小时前
🛠️ 为什么配置 ~/.ssh/config 后,Sourcetree 就能正常推送了?
前端
Sylus_sui2 小时前
Vue2 与 Vue3 数据双向绑定:区别与原理详解
前端·javascript·vue.js
ConardLi2 小时前
AI:我裂开了!现在的大模型评测究竟有多变态?
前端·人工智能·后端
这是你的玩具车吗2 小时前
能和爸妈讲明白的大模型原理
前端·人工智能·机器学习
霍理迪3 小时前
CSS文本样式
前端·css
Ashley_Amanda3 小时前
JavaScript 中 JSON 的处理方法
前端·javascript·json
+VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue宠物寄养系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计·宠物
烛阴3 小时前
C# 正则表达式(3):分组与捕获——从子串提取到命名分组
前端·正则表达式·c#
一 乐3 小时前
校园实验室|基于springboot + vue校园实验室管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端