Vue子组件Emit传值后表单修改影响父组件状态的解决方法
问题解决:Vue购物清单表单引用问题及清空表单实现
问题根源
你遇到的问题核心是表单里的product是响应式对象引用:当通过$emit('addRow', product)传递给父组件时,父组件只是把这个引用添加到了products数组中。后续修改表单输入时,本质是在修改同一个对象的属性,因此表格里的数据会同步变化。
解决方案
需要完成两个关键修改:
- 传递给父组件时,发送当前
product的独立副本,切断引用关联 - 点击添加按钮后,重置表单为新的空商品实例,同时保证
id唯一
修改AddProductForm.vue代码
<template> <div class="row q-gutter-sm"> <q-input filled v-model="product.name" label="Name" /> <!-- 用v-model.number确保price是数字类型 --> <q-input filled v-model.number="product.price" label="Price" /> <q-btn color="black" text-color="white" label="Add" @click="handleAddProduct" /> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import { type Product } from './models'; // 跟踪下一个商品的唯一id let nextId = 1; const product = ref<Product>({ id: nextId++, name: '', price: 0, }); const emit = defineEmits<{ addRow: [item: Product]; }>(); const handleAddProduct = () => { // 1. 创建当前product的副本,避免引用传递 const newProduct = { ...product.value }; // 2. 将副本发送给父组件 emit('addRow', newProduct); // 3. 重置表单为新的空商品实例,更新id product.value = { id: nextId++, name: '', price: 0, }; }; </script>
补充父组件示例(ShoppingListParent.vue)
如果还未实现父组件,以下是完整的状态管理示例:
<template> <div class="container"> <h2>购物清单</h2> <AddProductForm @add-row="handleAddProduct" /> <ShoppingListComponent :products="products" /> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import ShoppingListComponent from './ShoppingListComponent.vue'; import AddProductForm from './AddProductForm.vue'; import type { Product } from './models'; const products = ref<Product[]>([]); const handleAddProduct = (newProduct: Product) => { products.value.push(newProduct); }; </script>
关键说明
- 对象副本:使用扩展运算符
{ ...product.value }创建新对象,确保父组件添加的是独立实例,后续表单修改不会影响已添加的商品 - 唯一id:用
nextId变量跟踪id,避免Vue的v-for出现重复key的警告 - 表单重置:直接替换
product.value为新对象,比逐个修改属性更简洁,同时保证响应式更新
内容的提问来源于stack exchange,提问作者Yorian
相关产品推荐
相关产品推荐

