Vue.js 2.0:关闭模态组件时重置传入Props的问题
嘿,这个问题我在做Vue项目时碰到过好多次,本质是引用类型的数据绑定导致的状态污染,我给你两种靠谱的解决思路,按需选就行:
问题根源
你直接把父组件的currentCustomer对象作为props传给BillingAddressForm,而对象是引用类型——如果表单里用v-model直接绑定了billingAddress的属性(比如v-model="billingAddress.street"),用户编辑时其实是在修改父组件里的原对象数据,所以关闭模态框再打开,内容自然还是修改后的样子。就算表单内部做了浅拷贝,嵌套属性依然会关联父组件数据。
方案一:子组件维护独立状态(推荐)
让表单组件自己维护一份和props无关的本地数据,彻底切断引用关联,关闭模态框时自动重置:
在
BillingAddressForm组件内创建本地副本
用watch监听传入的billingAddressprops,每次模态框打开(props更新)时,深拷贝一份到本地数据:export default { props: ['billingAddress'], data() { return { localBillingAddress: {} } }, watch: { billingAddress: { immediate: true, // 组件初始化时就执行一次 handler(newAddr) { // 深拷贝,彻底切断引用 this.localBillingAddress = JSON.parse(JSON.stringify(newAddr)); // 如果项目用了lodash,用_.cloneDeep(newAddr)更稳妥(支持特殊类型) } } } }表单绑定本地数据
把表单里的v-model都改成绑定localBillingAddress的属性,比如:<input v-model="localBillingAddress.street" placeholder="街道"> <input v-model="localBillingAddress.city" placeholder="城市">提交时同步到父组件
当用户点击表单的“保存”按钮时,通过自定义事件把本地数据传给父组件:methods: { onSubmit() { this.$emit('update-billing', this.localBillingAddress); // 通知模态框关闭 this.$parent.$emit('close-modal'); // 或者根据你的模态框API调用关闭方法 } }父组件处理更新
父组件监听子组件的提交事件,更新currentCustomer:<sweet-modal ref="billingAddressModal" v-on:close="test"> <BillingAddressForm :billingAddress="currentCustomer" @update-billing="handleUpdateBilling" > </BillingAddressForm> </sweet-modal>methods: { handleUpdateBilling(updatedAddr) { this.currentCustomer = updatedAddr; this.$refs.billingAddressModal.close(); }, test() { // 关闭时不需要额外操作,下次打开模态框时,watch会自动重新拷贝最新的currentCustomer到子组件本地 } }
方案二:父组件层面重置数据(不修改子组件时用)
如果不想改动子组件,可以在父组件里保存原始数据快照,关闭模态框时恢复:
保存原始快照
打开模态框前,先深拷贝一份currentCustomer作为原始快照:data() { return { currentCustomer: {}, originalBillingAddr: {}, isSubmitted: false // 标记用户是否提交了表单 } }, methods: { openBillingModal() { this.originalBillingAddr = JSON.parse(JSON.stringify(this.currentCustomer)); this.isSubmitted = false; this.$refs.billingAddressModal.open(); } }关闭时判断是否重置
在模态框的close事件里,如果用户没提交表单,就恢复原始数据:test() { if (!this.isSubmitted) { this.currentCustomer = JSON.parse(JSON.stringify(this.originalBillingAddr)); } }, handleSubmit(updatedAddr) { this.currentCustomer = updatedAddr; this.isSubmitted = true; this.$refs.billingAddressModal.close(); }
关键注意点
- 必须用深拷贝:浅拷贝(比如
Object.assign({}, addr))只能处理第一层属性,嵌套对象依然会和父组件数据关联,导致重置不彻底。 - 如果你的账单地址包含特殊类型(比如日期对象、函数),
JSON.parse(JSON.stringify)会失效,这时候建议用lodash的_.cloneDeep方法。
内容的提问来源于stack exchange,提问作者David Turton

