当前位置: 首页 > 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.cnnetsun.cn/news/92972.html

相关文章:

  • Molecular Operating Environment (MOE) 完整安装与配置指南
  • LobeChat能否用于生成直播话术?电商主播提词器
  • 终极C++网络编程:构建高性能HTTP服务的完整指南
  • 显卡驱动终极清理指南:一键彻底解决兼容性问题
  • Zotero GPT:用AI重新定义文献管理效率
  • LobeChat与LangChain结合应用:打造复杂AI工作流
  • 突破60帧束缚:原神性能优化工具深度解析
  • 云计算作业—-V L AN实验
  • 当连锁巡检“听懂人话”:VLM技术下的智能运营新场景
  • 责任链模式(Chain of Responsibility):实现事件或请求的逐级处理与传递
  • SMUDebugTool深度探索:解锁AMD Ryzen系统的隐藏性能
  • JavaScript 中的单例模式:利用闭包、IIFE 或 ES Modules 实现线程安全的单例
  • CORS 机制中的预检请求(Preflight Request):为什么 OPTIONS 请求总是先于复杂请求发送?
  • Google Drive文件下载终极指南:简单快速解决下载难题
  • 面对一个新领域,如何快速摸清门道?试试“一键生成”研究地图
  • 终极指南:5步实现全球付费内容免费阅读
  • GBase 8s数据库SYSTIMESTAMP表达式介绍(上)
  • 从“秒级”到“毫秒级”:金仓如何让InfluxDB的“时序神话”黯然失色?
  • zotero-style插件深度解析:从零打造高效文献管理生态
  • 5倍推理加速:Axolotl缓存策略如何终结重复计算瓶颈
  • LobeChat能否部署在华为云弹性云服务器?国产化替代实践
  • LobeChat备份与恢复策略:防止重要对话丢失
  • Access Token 生命周期管理:详细设计 Token 的获取、缓存、续期和过期处理机制
  • 客户群 ID 与业务 ID 映射:设计高性能数据库表结构,实现 ChatID 与内部业务标签的快速关联
  • 代码随想录算法训练营Day48 | 108.冗余连接、109.冗余连接II
  • 微信网页版访问困境突破:3步安装wechat-need-web插件实战指南
  • MFC扩展库BCGControlBar Pro v37.1——支持Visual Studio 2026
  • 知乎专题策划:LobeChat是否真的值得入手?
  • 毕业论文AIGC全线飘红?揭秘5个“去AI化”核心手段,附保姆级工具清单
  • MTKClient:如何快速掌握联发科设备调试的核心技巧?