当前位置: 首页 > 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.jsqmd.com/news/101200/

相关文章:

  • 飞书文档批量导出终极指南:一键备份700+文档的完整解决方案
  • DownKyi视频下载神器:从入门到精通完全指南
  • 3大核心优势:XUnity Auto Translator新手实战教程
  • zotero-gpt终极指南:AI驱动的文献智能筛选革命
  • UnrealPakViewer完全指南:5大场景高效解析UE4 Pak文件
  • ncmdumpGUI:解锁网易云音乐加密格式的终极解决方案
  • 微信网页版终极解决方案:wechat-need-web插件完整使用指南
  • 让扩散模型「可解释」不再降质,开启图片编辑新思路
  • Android App 崩溃排查实战:如何利用 RUM 完整数据与符号化技术定位问题?
  • UnrealPakViewer完全指南:5步掌握UE4 Pak文件深度分析技巧
  • WeChatPad:3分钟搞定微信双设备同时在线,告别扫码烦恼!
  • SillyTavern一键迁移宝典:零数据丢失的AI对话前端升级全攻略
  • 基于Selenium的自动化Web数据采集实践
  • SillyTavern版本升级3步走:新手也能轻松搞定
  • 3步搞定百度网盘提取码!这个神器让你告别繁琐搜索
  • CTF进阶破局指南:避开90%选手的坑,从卡题到夺冠的新维度技巧
  • 2026互联网运营求职:数据驱动型简历模板TOP5深度测评
  • 小红书数据采集:5个关键步骤让你轻松获取精准营销数据
  • 谷歌传奇“院士”:Gemini核心秘方不会公开!大模型推理还有很大降本空间!AGI太远,我更喜欢3~5年的研究,登月计划:医疗
  • 天坑termius重置密码机制
  • Lonsdor K518 Pro FCV: Activate Suzuki License for European/American Key Programming
  • WindowsCleaner终极指南:告别C盘爆红的完整解决方案
  • WindowsCleaner:彻底拯救C盘空间的终极清理方案
  • 【神器】locoloader
  • 5大革新功能:Zotero-Style如何重构学术研究流程?
  • Lumafly模组管理器:空洞骑士玩家的完整解决方案
  • 随便写写
  • PHP 轻松处理千万行数据 内存不爆,服务器不卡
  • nltk 下载
  • Zotero GPT:用AI重新定义文献管理效率