vue项目子组件使用 dialog 弹框,如何实现父子组件弹框展示状态关联?

vue 项目,子组件使用 el-dialog 组件,想要实现在父组件可以控制子组件 dialog 的展示和隐藏,子组件自己可以控制 dialog 展示和隐藏,该如何实现?

1. 子组件(DialogComponent.vue)

子组件接受一个来自父组件的 prop,用来控制 dialog 的显示状态,并且当子组件内部需要改变 dialog 状态时,通过 $emit 发送一个事件给父组件。

<template>  
  <el-dialog  
    :visible.sync="localVisible"  
    title="提示"  
    @close="handleClose"  
  >  
    <!-- Dialog 内容 -->  
  </el-dialog>  
</template>  
  
<script>  
export default {  
  props: {  
    visible: {  
      type: Boolean,  
      default: false  
    }  
  },  
  data() {  
    return {  
      localVisible: this.visible  
    };  
  },  
  watch: {  
    visible(newVal) {  
      this.localVisible = newVal;  
    },  
    localVisible(newVal) {  
      this.$emit('update:visible', newVal);  
    }  
  },  
  methods: {  
    handleClose() {  
      this.localVisible = false;  
      // 如果需要,可以添加逻辑处理,如:  
      // this.$emit('someEvent', data);  
    }  
  }  
};  
</script>

注意:这里使用了 .sync 修饰符的简化版(.sync 本质上是监听一个自定义的 update 事件并更新 prop)。但在 Vue 3 中,.sync 修饰符的使用有所变化,并且在这里为了更清楚地展示过程,我们直接使用了 watch 和 $emit

2. 父组件

在父组件中,你定义一个变量来控制 dialog 的显示,并将这个变量传递给子组件作为 prop。同时,监听子组件发出的 update:visible 事件来更新这个变量。

<template>  
  <div>  
    <button @click="showDialog = true">打开 Dialog</button>  
    <DialogComponent :visible="showDialog" @update:visible="showDialog = $event" />  
  </div>  
</template>  
  
<script>  
import DialogComponent from './DialogComponent.vue';  
  
export default {  
  components: {  
    DialogComponent  
  },  
  data() {  
    return {  
      showDialog: false  
    };  
  }  
};  
</script>

3. 注意事项

  • .sync 修饰符的替代:在 Vue 3 中,.sync 修饰符的使用方式有所变化,但在这个例子中,我们直接使用了 watch 和 $emit 来达到 .sync 类似的效果,以便更清晰地理解数据流动的过程。
  • 组件间的通信:通过 props 和自定义事件(emit)是 Vue 组件间通信的基本方式之一,适用于父子组件之间的通信。
  • 状态管理:对于更复杂的应用,可能需要考虑使用 Vuex 或 Pinia 等状态管理库来管理跨组件的状态。

4..sync 修饰符的使用

.sync 修饰符在 Vue 3 中的使用方式有所变化。在 Vue 3 中,.sync 修饰符不再会隐式地监听 update: 开头的事件,而是被视为一个普通的自定义事件监听器的前缀,你仍然需要在子组件中显式地 $emit 带有 update: 前缀的事件,但 Vue 3 提供了 v-model 的多个变体来支持更复杂的场景,包括自定义组件的双向绑定。

子组件:

<template>  
  <div>  
    <!-- 假设我们有一个方法用来更新 value -->  
    <button @click="updateValue">Update</button>  
  </div>  
</template>  
  
<script>  
export default {  
  props: ['value'],  
  methods: {  
    updateValue() {  
      // 发送一个 update:value 事件,并传递新的值  
      this.$emit('update:value', newValue);  
    }  
  }  
}  
</script>

父组件:

<template>  
  <child-component :value.sync="someData"></child-component>  
</template>  
  
<script>  
import ChildComponent from './ChildComponent.vue';  
  
export default {  
  components: {  
    ChildComponent  
  },  
  data() {  
    return {  
      someData: 'initial value'  
    };  
  }  
}  
</script>

 

在这个例子中,.sync 修饰符使得父组件可以监听 update:value 事件,并自动将 someData 更新为事件传递过来的新值,而不需要显式地在父组件的模板中写 @update:value="someData = $event"

5、优化方案

<template>  
  <el-dialog  
    v-model:visible="visible"  
    title="提示"  
    @close="handleClose"  
  >  
    <!-- Dialog 内容 -->  
  </el-dialog>  
</template>  
  
<script>  
export default {  
  props: {  
    modelValue: {  
      type: Boolean,  
      default: false  
    }  
  },  
  computed: {  
    // 使用 computed 属性来代理 prop,这样可以在模板中直接使用 visible  
    visible: {  
      get() {  
        return this.modelValue;  
      },  
      set(value) {  
        this.$emit('update:modelValue', value);  
      }  
    }  
  },  
  methods: {  
    handleClose() {  
      this.visible = false; // 触发 setter,从而发出 update:modelValue 事件  
    }  
  }  
};  
</script>

使用 v-model 而不是 .sync:
在 Vue 3 中,虽然 .sync 修饰符仍然可用,但推荐使用 v-model 的变体来实现双向绑定。对于自定义组件,可以通过 modelValue 和 update:modelValue 来实现这一点。
简化子组件逻辑:
子组件可以只负责发出更新事件,而不必维护一个本地的 localVisible 状态。

上面的代码中,使用了 v-model:visible 来绑定 el-dialog 的 visible 属性,但这通常不是 el-dialog 组件的标准用法,因为 el-dialog 并不直接支持 v-model。实际上,你应该直接监听 close 事件并在父组件中处理它,或者通过其他方式(如上面的 handleClose 方法)来控制显示状态。但为了展示如何使用 v-model 在自定义组件中,我保留了这种写法。

父组件:

<template>  
  <div>  
    <button @click="showDialog = true">打开 Dialog</button>  
    <DialogComponent v-model:modelValue="showDialog" />  
  </div>  
</template>  
  
<script>  
import DialogComponent from './DialogComponent.vue';  
  
export default {  
  components: {  
    DialogComponent  
  },  
  data() {  
    return {  
      showDialog: false  
    };  
  }  
};  
</script>

注意:在父组件中,使用 v-model:modelValue 来绑定 showDialog 变量,这与 Vue 3 中推荐的自定义组件 v-model 用法一致。这样,父组件和子组件就可以通过 showDialog 变量来双向控制 el-dialog 的显示了。

 

 
posted @ 2024-07-03 11:36  蓓蕾心晴  阅读(1158)  评论(0编辑  收藏  举报