当前位置: 首页 > news >正文

VUE3:深入浅出探究pinia、provide\inject在多层组件页面是怎么使用的

1. Pinia 状态管理

什么是 Pinia?

Pinia是 Vue 3 官方推荐的状态管理库,可以理解为一个"全局数据仓库"。

为什么需要它?想象一下,你有一个购物车数据,需要在多个页面(首页、商品页、结算页)共享。如果用 props 一层层传递会很麻烦,Pinia 就是解决这个问题的。

安装 Pinia

npm install pinia

使用步骤

第一步:在 main.js 中注册 Pinia
// main.js import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) const pinia = createPinia() app.use(pinia) app.mount('#app')
第二步:创建 Store(数据仓库)
// src/stores/counter.js import { defineStore } from 'pinia' import { ref, computed } from 'vue' // defineStore 第一个参数是 store 的唯一标识(名字) export const useCounterStore = defineStore('counter', () => { // ========== state(数据)========== // 就像组件中的 ref,存放响应式数据 const count = ref(0) const name = ref('小明') // ========== getters(计算属性)========== // 就像组件中的 computed const doubleCount = computed(() => count.value * 2) // ========== actions(方法)========== // 修改数据的方法 function increment() { count.value++ } function decrement() { count.value-- } // 异步操作也可以放在 actions 中 async function asyncIncrement() { // 模拟接口请求 await new Promise(resolve => setTimeout(resolve, 1000)) count.value++ } // 必须 return 出去才能在组件中使用 return { count, name, doubleCount, increment, decrement, asyncIncrement } })
第三步:在组件中使用 Store

爷爷组件 (GrandParent.vue)

<template> <div class="grandparent"> <h2>👴 爷爷组件</h2> <p>从 Pinia 获取的 count: {{ counterStore.count }}</p> <p>双倍 count: {{ counterStore.doubleCount }}</p> <button @click="counterStore.increment">爷爷点击 +1</button> <!-- 嵌套父组件 --> <ParentComponent /> </div> </template> <script setup> import { useCounterStore } from '@/stores/counter' import ParentComponent from './ParentComponent.vue' // 获取 store 实例,直接使用即可 const counterStore = useCounterStore() </script>

父组件 (ParentComponent.vue)

<template> <div class="parent"> <h3>👨 父组件</h3> <p>从 Pinia 获取的 count: {{ counterStore.count }}</p> <button @click="counterStore.decrement">父亲点击 -1</button> <!-- 嵌套子组件 --> <ChildComponent /> </div> </template> <script setup> import { useCounterStore } from '@/stores/counter' import ChildComponent from './ChildComponent.vue' // 任何组件都可以直接获取同一个 store const counterStore = useCounterStore() </script>

孙子组件 (ChildComponent.vue)

<template> <div class="child"> <h4>👶 孙子组件</h4> <p>从 Pinia 获取的 count: {{ counterStore.count }}</p> <button @click="counterStore.asyncIncrement">孙子异步 +1(1秒后)</button> </div> </template> <script setup> import { useCounterStore } from '@/stores/counter' // 三层组件都能访问同一份数据! const counterStore = useCounterStore() </script>

Pinia 小结

概念

说明

Store

全局数据仓库,所有组件都能访问

State

存放数据的地方(用 ref 或 reactive)

Getters

计算属性(用 computed)

Actions

修改数据的方法(普通函数,可以是异步的)


2. Provide / Inject 依赖注入

什么是 Provide / Inject?

这是 Vue 内置的"跨层级传值"方案,不需要安装额外的库。

  • provide(提供):祖先组件提供数据
  • inject(注入):后代组件接收数据

与 Pinia 的区别:Provide/Inject 的数据是"局部的",只在当前组件树内共享;而 Pinia 是"全局的"。

基本使用

爷爷组件(提供数据)
<template> <div class="grandparent"> <h2>👴 爷爷组件 - Provide 示例</h2> <p>爷爷的消息: {{ message }}</p> <p>爷爷的主题色: {{ theme }}</p> <button @click="changeTheme">切换主题</button> <ParentProvide /> </div> </template> <script setup> import { ref, provide } from 'vue' import ParentProvide from './ParentProvide.vue' // ========== 定义要共享的数据 ========== const message = ref('来自爷爷的问候~') const theme = ref('light') // 切换主题的方法 const changeTheme = () => { theme.value = theme.value === 'light' ? 'dark' : 'light' } // ========== 使用 provide 提供数据 ========== // provide(key, value) // key: 字符串或 Symbol,用于标识 // value: 要共享的数据 // 提供普通数据 provide('message', message) // 提供响应式数据(子组件能感知变化) provide('theme', theme) // 提供方法(让子组件也能修改数据) provide('changeTheme', changeTheme) // 提供对象(包含多个相关数据) provide('userInfo', { name: '张三', age: 60, role: 'grandparent' }) </script>
父组件(中间层,不需要处理)
<template> <div class="parent"> <h3>👨 父组件</h3> <p>我是中间层,不需要 inject,数据可以跳过我直接传给孙子</p> <ChildInject /> </div> </template> <script setup> import ChildInject from './ChildInject.vue' // 注意:父组件不需要做任何事,数据会"穿透"过去 </script>
孙子组件(注入数据)
<template> <div class="child" :class="theme"> <h4>👶 孙子组件 - Inject 示例</h4> <!-- 使用注入的数据 --> <p>收到爷爷的消息: {{ message }}</p> <p>当前主题: {{ theme }}</p> <p>用户信息: {{ userInfo.name }}, {{ userInfo.age }}岁</p> <!-- 调用爷爷提供的方法 --> <button @click="changeTheme">孙子也能切换主题</button> </div> </template> <script setup> import { inject } from 'vue' // ========== 使用 inject 接收数据 ========== // inject(key) 或 inject(key, 默认值) // 接收响应式数据 const message = inject('message') const theme = inject('theme') // 接收方法 const changeTheme = inject('changeTheme') // 接收对象 const userInfo = inject('userInfo') // 设置默认值(如果祖先没有 provide,就用默认值) const notExist = inject('notExist', '这是默认值') </script> <style scoped> .light { background: #fff; color: #333; } .dark { background: #333; color: #fff; } </style>

Provide / Inject 小结

特点

说明

适用场景

跨多层组件传值,避免 props 层层传递

响应式

如果 provide 的是 ref/reactive,子组件能响应变化

作用范围

只在当前组件树内有效

与 Pinia 对比

更轻量,但没有 Pinia 的状态管理能力

http://www.zskr.cn/news/111986.html

相关文章:

  • zotero-gpt终极指南:AI驱动的文献智能筛选革命
  • SillyTavern一键迁移宝典:零数据丢失的AI对话前端升级全攻略
  • WeChatPad:3分钟搞定微信双设备同时在线,告别扫码烦恼!
  • 基于Selenium的自动化Web数据采集实践
  • 谷歌传奇“院士”:Gemini核心秘方不会公开!大模型推理还有很大降本空间!AGI太远,我更喜欢3~5年的研究,登月计划:医疗
  • 天坑termius重置密码机制
  • 【神器】locoloader
  • Zotero GPT:用AI重新定义文献管理效率
  • 当连锁巡检“听懂人话”:VLM技术下的智能运营新场景
  • LobeChat与LangChain结合应用:打造复杂AI工作流
  • 2025-12-16-Nature | 本周最新文献速递
  • DownKyi实战宝典:5大核心技巧让B站视频下载效率翻倍
  • 一键镜像烧录神器:告别传统写入困扰的终极解决方案
  • LobeChat企业版功能前瞻:更多权限与审计能力
  • ztl_蓝桥杯python_基础语法_数据容器与列表 - Sky
  • 总体
  • AI 照片修复神器:如何用 AI 恢复老照片高清细节
  • MFC扩展库BCGControlBar Pro v37.1——支持Visual Studio 2026
  • pve安装Alpine Linux
  • Google Drive高效下载工具使用指南
  • 循环依赖报错
  • Windows-PowerShell-prompt
  • 5.服务器内部错误 500
  • why people like English but not Englishman?
  • 纠结 15 万新能源 SUV 买哪款?实测数据告诉你答案
  • 百度网盘解析工具终极指南:3分钟告别下载限速烦恼
  • OpenCore Legacy Patcher:让老款Mac重获新生的升级神器?
  • 六音音源修复技术全解析:从原理到实践
  • LobeChat撰写技术文档体验报告
  • HTML Learn Data Day 0