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

Vue3父子组件数据双向绑定示例

以下是基于Vue3的代码示例,实现父组件表格行点击通过对话框子组件编辑数据的功能:

vue

<!-- 父组件 ParentComponent.vue -->
<template><el-table :data="tableData" @row-click="handleRowClick" style="width: 100%"><el-table-column prop="name" label="Name" /><el-table-column prop="age" label="Age" /><el-table-column prop="email" label="Email" /></el-table><ChildDialogv-model="dialogVisible":row-data="selectedRow"@confirm="handleDataUpdate"/>
</template><script setup>
import { ref } from 'vue'
import ChildDialog from './ChildDialog.vue'const tableData = ref([{ id: 1, name: 'John', age: 30, email: 'john@example.com' },{ id: 2, name: 'Jane', age: 25, email: 'jane@example.com' }
])const dialogVisible = ref(false)
const selectedRow = ref(null)const handleRowClick = (row) => {selectedRow.value = rowdialogVisible.value = true
}const handleDataUpdate = (updatedData) => {const index = tableData.value.findIndex(item => item.id === updatedData.id)if (index !== -1) {tableData.value.splice(index, 1, updatedData)}
}
</script>

vue

<!-- 子组件 ChildDialog.vue -->
<template><el-dialogv-model="modelValue"title="Edit Row"width="500px"@close="handleClose"><el-form label-width="80px"><el-form-item label="Name"><el-input v-model="localData.name" /></el-form-item><el-form-item label="Age"><el-input v-model.number="localData.age" /></el-form-item><el-form-item label="Email"><el-input v-model="localData.email" /></el-form-item></el-form><template #footer><el-button @click="modelValue = false">Cancel</el-button><el-button type="primary" @click="handleConfirm">Confirm</el-button></template></el-dialog>
</template><script setup>
import { ref, watch, defineProps, defineEmits } from 'vue'const props = defineProps({modelValue: Boolean,rowData: Object
})const emit = defineEmits(['update:modelValue', 'confirm'])const localData = ref({...props.rowData})watch(() => props.rowData, (newVal) => {localData.value = {...newVal}
})watch(() => props.modelValue, (newVal) => {if (!newVal) returnlocalData.value = {...props.rowData}
})const handleConfirm = () => {emit('confirm', {...localData.value})emit('update:modelValue', false)
}const handleClose = () => {emit('update:modelValue', false)
}
</script>

关键实现说明:

  1. 父子组件通信:

  • 使用v-model双向绑定对话框状态

  • 通过props传递行数据

  • 通过emit事件进行数据更新通知

  1. 数据管理:

  • 子组件使用localData维护数据副本

  • 使用watch同步父组件传入的最新数据

  • 在对话框打开时重置为原始数据

  1. 数据更新流程:

  2. 点击表格行时缓存选中数据并打开对话框

  3. 子组件深度拷贝数据保证独立性

  4. 修改数据后通过confirm事件回传父组件

  5. 父组件更新原始数据源完成响应式更新

  6. 注意事项:

  • 使用{...object}进行对象浅拷贝

  • 数字类型字段使用v-model.number修饰符

  • 通过splice方法触发数组响应式更新

  • 对话框关闭时重置本地数据

该实现方案完整实现了需求中的三个核心功能点,并保证了数据修改的独立性和响应式更新。

代码中关于两个watch的说明:

在 Vue3 的代码示例中,这两个 watch 各有不同的职责,后者并非多余。它们的核心区别如下:


1️⃣ 第一个 watch 的作用props.rowData 的变化监听

javascript

watch(() => props.rowData, (newVal) => {localData.value = {...newVal}
})
  • 触发条件:当父组件传递的 rowData 引用发生变化时(例如切换不同行)。

  • 典型场景:用户点击不同表格行时,父组件传入新的 rowData,子组件需同步更新本地数据。

  • 必要性:确保子组件能响应父组件数据源的变更。


2️⃣ 第二个 watch 的作用props.modelValue(对话框状态)的变化监听

javascript

watch(() => props.modelValue, (newVal) => {if (!newVal) returnlocalData.value = {...props.rowData}
})
  • 触发条件:当对话框重新打开时(无论是否切换行)。

  • 典型场景:用户关闭对话框后,再次打开同一行进行编辑。

  • 必要性:解决对象引用未变时的数据同步问题。如果用户未保存修改就关闭对话框,再次打开时需要丢弃未保存的改动,还原到原始数据。


🚨 为什么需要两个 watch?

场景第一个 watch 是否生效第二个 watch 是否生效问题描述
点击不同行打开对话框✅ 生效❌ 不生效需通过第一个 watch 同步新行数据
同一行重复打开对话框❌ 不生效(引用未变)✅ 生效需通过第二个 watch 重置本地数据,丢弃未保存的修改
父组件外部更新数据后打开对话框✅ 生效✅ 生效双重保障确保数据同步

🔧 代码优化建议

如果希望进一步简化逻辑,可合并为一个 watch,但需明确处理两种场景:

javascript

watch([() => props.rowData, () => props.modelValue],([newRowData, isOpen]) => {if (isOpen) {localData.value = {...newRowData}}},{ immediate: true }
)
  • 原理:当对话框打开时(modelValue 为 true),强制用最新的 rowData 重置本地数据。

  • 代价:可能牺牲部分性能(频繁触发),但逻辑更集中。


📝 总结

  • 保留两个 watch:更符合职责单一原则,分别处理数据引用变化和对话框状态变化。

  • 关键点:确保用户在重复打开同一行时,总能基于父组件的最新数据重新开始编辑,避免脏数据残留。


文章转载自:

http://q8PhzKVH.mxbks.cn
http://cfD538la.mxbks.cn
http://hntCKhcL.mxbks.cn
http://tn19O6Ws.mxbks.cn
http://p7LDh5u5.mxbks.cn
http://idvllUHl.mxbks.cn
http://C4v10qdx.mxbks.cn
http://NX7MFRrU.mxbks.cn
http://Xi60ZuM1.mxbks.cn
http://DcIs8SKu.mxbks.cn
http://H08jaHwd.mxbks.cn
http://F1cxQGIF.mxbks.cn
http://bOhhw4d6.mxbks.cn
http://d6LDfsOA.mxbks.cn
http://JKpUfZSK.mxbks.cn
http://9dgxu2ht.mxbks.cn
http://5Ss4X1nD.mxbks.cn
http://30PAR6eQ.mxbks.cn
http://DOpRgF7I.mxbks.cn
http://EW828bm9.mxbks.cn
http://jg5W7K5y.mxbks.cn
http://x74ObiKm.mxbks.cn
http://96KqnvZ4.mxbks.cn
http://ZOnjsOwA.mxbks.cn
http://f7zzjXaC.mxbks.cn
http://daoj3Bdu.mxbks.cn
http://JnWU7XdB.mxbks.cn
http://74yQNcdd.mxbks.cn
http://vQH66A1F.mxbks.cn
http://tQWGU7Vr.mxbks.cn
http://www.dtcms.com/a/136762.html

相关文章:

  • VS qt 联合开发环境下的多国语言翻译
  • 【AI飞】AutoIT入门五(拐点):python操控autoit
  • html-css样式
  • 关于MacOS使用Homebrew的详细介绍
  • MetaLiveX:用AI重新定义直播互动的边界
  • C# JSON
  • 吉尔吉斯斯坦工商会代表团赴齐河德瑞新能源汽车考察
  • 快速入手-基于python和opencv的人脸检测
  • Java学习手册:Java锁机制详解
  • 【python】OpenCV—Tracking(10.6)—People Counting
  • Paimon的InternalRow 解析(一)
  • 14.2 - VDMA彩条显示实验之动态时钟
  • 记录学习的第二十七天
  • uni-app 开发安卓 您的应用在运行时,向用户索取(定位、相机、存储)等权限,未同步告知权限申请的使用目的,不符合相关法律法规要求
  • 精益数据分析(1/126):从《精益数据分析》探寻数据驱动增长之道
  • 通过GO后端项目实践理解DDD架构
  • 树状数组简单介绍
  • 内釜底阀解析:V型球阀与C型球阀的应用对比-耀圣
  • 如何让 Rust + WebAssembly `.wasm` 更小更快?从构建配置到源码重构的全流程指南
  • 国产DPU芯片+防火墙,能否引领网络安全新跨越?
  • 使用 Java 8 Stream实现List重复数据判断
  • C# 类型、存储和变量(类型是一种模板)
  • SQL Server 2022 安装常见问题及解决方法
  • AI编程新纪元:GitHub Copilot、CodeGeeX与VS2022的联合开发实践
  • CobaltStrike
  • 工作记录4
  • Spring Boot 中的自动配置原理
  • Flutter使用flutter_driver进行自动化测试
  • Python刷题笔记1
  • Golang|KVBitcask