Vue 3中如何通过父组件的@click事件修改子组件的ref变量?
Got it, let's work through this step by step. The core issue here is that your ConfirmModal component is managing its own open state internally, which means your parent component can't directly trigger it to open when the TrashIcon is clicked. We'll fix this with two straightforward approaches—pick the one that fits your workflow best:
Approach 1: Use v-model (Recommended)
This follows Vue's preferred two-way binding pattern, making state flow clear and maintainable.
Step 1: Update ConfirmModal.vue to accept external state
We'll convert the internal open ref into a prop, and emit an event when the modal needs to close so the parent can update the state:
<template> <TransitionRoot as="template" :show="open"> <Dialog as="div" class="relative z-10" @close="handleClose"> <!-- Keep your existing modal content here --> </Dialog> </TransitionRoot> </template> <script setup> // Define props to accept the open state from parent const props = defineProps({ open: { type: Boolean, default: false } }) // Define emit to notify parent when state needs to change const emit = defineEmits(['update:open']) // Handle dialog close by emitting the update event const handleClose = () => { emit('update:open', false) } </script>
Step 2: Update the parent component (Edit.vue)
Now we'll manage the modal's open state in the parent and bind it to the child using v-model:
If using Options API:
<template> <TrashIcon @click="openDeleteModal"/> <ConfirmModal v-model:open="isDeleteModalOpen" :title="'Delete client'" :message="'Are you sure you want to delete this client? This action cannot be undone.'" /> </template> <script> import ConfirmModal from '@/Components/ConfirmModal.vue'; export default { components: { ConfirmModal }, data() { return { isDeleteModalOpen: false // Track modal state in parent } }, methods: { openDeleteModal() { this.isDeleteModalOpen = true; // Toggle state on icon click } } } </script>
If using Composition API (script setup):
<template> <TrashIcon @click="isDeleteModalOpen = true"/> <ConfirmModal v-model:open="isDeleteModalOpen" :title="'Delete client'" :message="'Are you sure you want to delete this client? This action cannot be undone.'" /> </template> <script setup> import { ref } from 'vue'; import ConfirmModal from '@/Components/ConfirmModal.vue'; const isDeleteModalOpen = ref(false); // Track modal state </script>
Approach 2: Expose a Method from the Child Component
If you prefer keeping state encapsulated in the child, expose an openModal method the parent can call directly via a ref:
Step 1: Update ConfirmModal.vue to expose the method
<template> <TransitionRoot as="template" :show="open"> <Dialog as="div" class="relative z-10" @close="open = false"> <!-- Keep your existing modal content here --> </Dialog> </TransitionRoot> </template> <script setup> import { ref } from 'vue'; const open = ref(false); // Expose method to parent defineExpose({ openModal: () => { open.value = true; } }) </script>
Step 2: Update the parent component (Edit.vue)
<template> <TrashIcon @click="confirmModalRef?.openModal()"/> <ConfirmModal ref="confirmModalRef" :title="'Delete client'" :message="'Are you sure you want to delete this client? This action cannot be undone.'" /> </template> <script setup> import { ref } from 'vue'; import ConfirmModal from '@/Components/ConfirmModal.vue'; // Create ref to access the child component instance const confirmModalRef = ref(null); </script>
Why This Works
- Approach 1 lifts state to the parent, making it easy to track and manage the modal's visibility across your app—this is the most scalable option.
- Approach 2 keeps state internal to the child, which is great if the modal only needs to be controlled in one specific place.
Either way, clicking the TrashIcon will now trigger the modal to open exactly as you need!
内容的提问来源于stack exchange,提问作者RyanJG

