Vue三层组件传prop搭配PrimeVue Dialog出现prop突变报错求解
问题根源
- Prop修改报错:你在
BaseModal中直接用:visible.sync="show"将PrimeVue Dialog的显隐状态绑定到了父组件传入的showProp,.sync修饰符会自动尝试修改绑定的变量,但Vue规定子组件不能直接修改父组件传递的Prop,因此触发了直接修改Prop的报错。 - 需点击两次打开模态框:点击模态框右上角关闭按钮时,Dialog内部已经将显隐状态改为false,但上层
ProductList中的activeModal状态没有同步重置,仍然保留着之前打开的产品ID。此时点击新的产品链接,第一次触发toggleModal时会先把非0的activeModal重置为0,不会打开新模态框,第二次点击才会把activeModal设为对应ID完成打开,因此需要点击两次。
修复方案
按三层组件从上到下依次修改即可:
1. 修正BaseModal组件(最底层)
不要直接绑定Prop到Dialog的.sync修饰符,通过内部计算属性中转状态,关闭时向上抛出更新事件:
<template> <div> <Dialog :header="header" :visible.sync="innerShow" :modal="true" :closable="true" @hide="doit"> <slot /> </Dialog> </div> </template> <script> export default { props: { show: Boolean, header: String, }, computed: { innerShow: { get() { return this.show }, set(val) { // 状态变化时向上抛出更新事件,通知父组件修改Prop来源 this.$emit('update:show', val) } } }, methods: { doit: function () { // 关闭时触发状态更新 this.innerShow = false }, } } </script>
2. 修正ProductForm组件(中间层)
接收底层抛出的更新事件,继续向上层抛出同步状态:
<template> <div> <!-- 用.sync修饰符绑定show,自动接收子组件的update:show事件 --> <BaseModal :show.sync="show" :header="product.name"> <span class="p-float-label"> <InputText id="name" type="text" :value="product.name" /> <label for="name">Product</label> </span> </BaseModal> </div> </template> <script> import BaseModal from "../_modals/BaseModal"; export default { props: ["product", "show"], components: { BaseModal }, // 监听show Prop的变化,向上层抛出更新事件 watch: { show(newVal) { this.$emit('update:show', newVal) } } }; </script>
3. 修正ProductList组件(最上层)
接收中间层抛出的更新事件,同步重置activeModal状态,保证上下层状态一致:
<template> <Column field="id" headerStyle="width: 5%"> <template #body="slotProps"> <!-- 监听子组件抛出的关闭事件 --> <ProductForm :product="slotProps.data" :show="showModal(slotProps.data.id)" @update:show="handleModalClose" /> <a href="#" @click.stop="toggleModal(slotProps.data.id)"> <span class="pi pi-external-link"> </span> </a> </template> </Column> </template> <script> import ProductForm from "./forms/ProductForm"; export default { data() { return { activeModal: 0, } }, components: { ProductForm }, methods: { toggleModal: function (id) { // 简化逻辑:当前打开的是同一个模态框则关闭,否则打开对应模态框 this.activeModal = this.activeModal === id ? 0 : id; }, showModal: function (id) { return this.activeModal === id; }, // 接收子组件的关闭事件,重置activeModal handleModalClose(val) { if (!val) { this.activeModal = 0 } } }, } </script>
内容的提问来源于stack exchange,提问作者Kenny
相关产品推荐
相关产品推荐

