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

Vue3祖先后代组件数据双向同步实现方法

在 Vue3 中实现祖先后代组件的双向数据同步,可以通过组合式 API 的 provide/inject 配合响应式数据实现。以下是两种常见实现方案:


方案一:共享响应式对象 + 方法

html

<!-- 祖先组件 -->
<script setup>
import { ref, provide } from 'vue'const value = ref('初始值')// 提供响应式数据与更新方法
const updateValue = (newVal) => { value.value = newVal }
provide('data', { value, updateValue })
</script><!-- 后代组件 -->
<script setup>
import { inject } from 'vue'const { value, updateValue } = inject('data')
</script>

方案二:计算属性双向绑定

html

<!-- 祖先组件 -->
<script setup>
import { ref, computed, provide } from 'vue'const innerValue = ref('初始值')// 通过计算属性实现双向绑定
provide('data', computed({get: () => innerValue.value,set: (val) => { innerValue.value = val }
}))
</script><!-- 后代组件 -->
<script setup>
import { inject } from 'vue'const data = inject('data')
</script><!-- 使用时直接 v-model 绑定 -->
<input v-model="data">

方案三:Vuex/Pinia 全局状态管理(适合复杂场景)

js

// store.js
import { defineStore } from 'pinia'export useStore = defineStore('data', () => {const value = ref('初始值')return { value }
})<!-- 任意组件 -->
<script setup>
import { useStore } from './store'
const store = useStore()
</script><!-- 直接绑定 -->
<input v-model="store.value">

最佳实践建议:

  1. 简单场景使用 provide/inject + 响应式对象

  2. 中大型项目推荐使用 Pinia

  3. 需要严格数据流时,建议通过方法修改数据而非直接赋值

  4. 使用 TypeScript 时建议定义 InjectionKey 增强类型提示

ts

// 类型安全版本
import type { InjectionKey } from 'vue'interface DataType {value: Ref<string>update: (val: string) => void
}const dataKey: InjectionKey<DataType> = Symbol()// 祖先组件
provide(dataKey, { value, updateValue })// 后代组件
const { value, update } = inject(dataKey)! // 非空断言

实例代码:

祖先组件:

<script setup lang="ts" name="SampleInput">
......
// 受理样品表格数据
const applySampleTableData = ref<ApplySample[]>([]);// 提供数据给后代
// 受理样品列表
provide("applySampleList", readonly(applySampleTableData)); // applySampleTableData是个Ref对象,不需要.value,传递ref对象本身(响应式数据)// 提供函数给后代,接收受理样品
provide("transmitApplySampleListData", receiveApplySampleListData);// 接收受理样品
const receiveApplySampleListData = (applySamples: ApplySample[]) => {applySampleTableData.value = applySamples;
};
......
</script>

后代组件:

<script setup lang="ts" name="CommonApplySampleTable">
......
// 接收祖先提供的数据
// 受理样品列表
const applySampleList = inject<Ref<ApplySample[]>>("applySampleList", ref([]));// 注入祖先提供的函数
// 将受理样品列表数据发送给祖先
const sendApplySampleListData = inject("transmitApplySampleListData", (data: ApplySample[]) => {});// 受理样品列表-本地副本
const localApplySampleList = ref<ApplySample[]>([]);
// 标识:是否来自祖先的更新。防循环处理:通过 isUpdatingFromAncestry 和 nextTick() 确保祖先组件更新不会触发后代组件同步
let isUpdatingFromAncestry = false;// 监听祖先组件的 applySampleList 变化,更新本地的 localApplySampleList
watch(() => applySampleList.value,async () => {// 标识是否来自祖先组件的更新为:是isUpdatingFromAncestry = true;// 拷贝祖先组件的 applySampleList 数据到本地的 localApplySampleListlocalApplySampleList.value = reactive(JSON.parse(JSON.stringify(toRaw(applySampleList.value))));// 等待 DOM 更新完成await nextTick();// 标识是否来自祖先组件的更新为:否isUpdatingFromAncestry = false;},{ deep: true }
);// 监听本地的 localApplySampleList 变化,同步数据给祖先组件
watch(() => localApplySampleList.value,() => {// 判断是否来自祖先组件的更新为:否// 也就是自身更新的,才同步数据给祖先组件,祖先组件更新过来,则不需要再更新回去,从而防止循环if (!isUpdatingFromAncestry) {// 同步数据给祖先组件sendApplySampleListData(localApplySampleList.value);}},{ deep: true }
);
......
</script>

 


文章转载自:

http://fRM61Tz6.Lzrpy.cn
http://DFEJRQSQ.Lzrpy.cn
http://Cncd7BOg.Lzrpy.cn
http://Mm6wBmyO.Lzrpy.cn
http://7ZdxUMAC.Lzrpy.cn
http://uPnY72Ta.Lzrpy.cn
http://LVBrrXKA.Lzrpy.cn
http://xeKSUghF.Lzrpy.cn
http://kW8ESbaX.Lzrpy.cn
http://Y1O3IpEp.Lzrpy.cn
http://QY2equVV.Lzrpy.cn
http://dzszvuY5.Lzrpy.cn
http://TKwh8Fdo.Lzrpy.cn
http://xWLiVd1f.Lzrpy.cn
http://wLXirkRY.Lzrpy.cn
http://V5jdkbpz.Lzrpy.cn
http://XgjQ9YnM.Lzrpy.cn
http://dRCkYCrV.Lzrpy.cn
http://5wfYdN57.Lzrpy.cn
http://rkhlDiJU.Lzrpy.cn
http://Q8WXdKdQ.Lzrpy.cn
http://16scs3MW.Lzrpy.cn
http://NiiPBSzh.Lzrpy.cn
http://GlkLfrGW.Lzrpy.cn
http://QNyGU1Gi.Lzrpy.cn
http://emI13ojf.Lzrpy.cn
http://dXrCTjmP.Lzrpy.cn
http://3Py9F59l.Lzrpy.cn
http://Ob8RgDK4.Lzrpy.cn
http://d5ITs6xh.Lzrpy.cn
http://www.dtcms.com/a/151342.html

相关文章:

  • TypeScript-知识点梳理
  • 阿里云 AI 搜索开放平台:RAG智能化工作流助力 AI 搜索
  • 【数据结构和算法】6. 哈希表
  • Hive中Map和Reduce阶段的分工
  • C++笔记-stack_queue(含deque,priority_queue,仿函数的讲解)
  • NHANES指标推荐:CTI
  • NOIP2012提高组.同余方程
  • Java基础复习(JavaSE进阶)第九章 网络编程
  • 考研单词笔记 2025.04.23
  • 脂质体挤出器有哪些知名品牌?
  • 2025深圳中兴通讯安卓开发社招面经
  • 【金仓数据库征文】从Oracle到KingbaseES的语法兼容与迁移
  • Spring Boot 项目:如何在 JAR 运行时读取外部配置文件
  • 【每日八股】复习计算机网络 Day4:TCP 协议的其他相关问题
  • 【Java学习笔记】random的使用
  • 并行RANSAC平面拟合(C++)
  • [特殊字符]‍[特殊字符]Linux驱动开发入门 | 并发与互斥机制详解
  • ActiveMQ 核心概念与消息模型详解(二)
  • centos7 设置EMQX开机自启动(创建init.d脚本来设置emqx的自启动服务)
  • 文档构建:Sphinx全面使用指南 — 实战篇
  • leetcode 二分查找应用
  • 未曾设想的道路1
  • idea无法下载源代码
  • 使用Python模拟子弹与子弹的碰撞
  • 蓝桥杯 19. 最大比例
  • 阳光乳业2024年营收、利润双降:囿于一隅,市场单一化困局何解?
  • 抱佛脚之学SSM五
  • Rust 学习笔记:安装 Rust
  • Qt实现语言切换的完整方案
  • 一,开发环境安装