You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue父组件如何不迁移子组件ref,访问其状态并执行条件操作?

解决方案:父组件访问子组件内部ref状态(无需迁移ref到父组件)

针对你的需求——在父组件的enterLeaveNav函数中,仅当子组件Nav的isHamburgerClosed为true时才切换isNavClosed,这里提供几种可行的实现方式:


方案1:子组件通过defineExpose暴露状态

这是最直接的方式,子组件将内部ref暴露给父组件,父组件通过模板ref获取子组件实例来访问状态。

修改Nav.vue

在<script setup>中用defineExpose暴露需要的状态和方法:

<script setup>
import { ref } from 'vue'

const isHamburgerClosed = ref(true)
const toggleNav = () => {
  isHamburgerClosed.value = !isHamburgerClosed.value
  // 保留你原有的菜单切换逻辑
}

// 暴露给父组件访问
defineExpose({
  isHamburgerClosed,
  toggleNav
})
</script>

<template>
  <div
    class="hamburgerMenu"
    :class="isHamburgerClosed ? 'hamburgerMenuMarginLeft2' : 'hamburgerMenuMarginLeft80'"
    @click="toggleNav"
  >
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
  </div>
</template>

修改父组件

添加模板ref绑定Nav组件,在enterLeaveNav中通过ref访问子组件状态:

<script setup>
import Header from "@/Components/Header.vue";
import Nav from "@/Components/Nav.vue";
import { ref } from "vue";

const isScroll = ref(false);
const isNavClosed = ref(false);
// 定义模板ref获取Nav组件实例
const navRef = ref(null)

function setIsNavClosed() {
    isNavClosed.value = !isNavClosed.value;
}

function enterLeaveNav() {
    isScroll.value = !isScroll.value;
    // 安全访问子组件暴露的状态
    if (navRef.value?.isHamburgerClosed) {
        isNavClosed.value = !isNavClosed.value;
    }
}
</script>

<template>
    <div>
        <header class="header container">
            <Header />
        </header>
        <div class="container-fluid">
            <div class="row g-0">
                <nav
                    class="p-0 nav"
                    :class="[
                        isScroll ? 'overflowScroll' : 'overflowHidden',
                        isNavClosed ? 'width833' : 'width1633',
                    ]"
                    @mouseenter="enterLeaveNav"
                    @mouseleave="enterLeaveNav"
                >
                    <!-- 绑定模板ref -->
                    <Nav ref="navRef" @open-close-nav="setIsNavClosed" />
                </nav>
                <main
                    class="ps-5"
                    :class="[
                        isNavClosed
                            ? 'offset-md-1 col-md-10'
                            : 'offset-md-2 col-md-9',
                    ]"
                    style="margin-top: 100px"
                >
                    <slot name="content" />
                </main>
            </div>
        </div>
    </div>
</template>

方案2:修复组合式函数的状态共享问题

你之前的组合式函数每次调用都会创建新的ref实例,导致父子组件状态不同步。可以改成单例模式,让所有组件共享同一状态:

修改useNavigation.js

让组合式函数只初始化一次状态:

import { ref } from "vue";

// 内部保存单例状态,避免重复创建
let navigationState = null;

export function useNavigation() {
    if (!navigationState) {
        const isNavClosed = ref(false);
        const isHamburgerClosed = ref(false);
        const isScroll = ref(false);

        function toggleNav() {
            isNavClosed.value = !isNavClosed.value;
            isHamburgerClosed.value = !isHamburgerClosed.value;
        }

        function enterLeaveNav() {
            if (isHamburgerClosed.value) {
                isNavClosed.value = !isNavClosed.value;
            }
            isScroll.value = !isScroll.value;
        }

        navigationState = {
            isScroll,
            isNavClosed,
            isHamburgerClosed,
            toggleNav,
            enterLeaveNav,
        };
    }
    return navigationState;
}

父组件使用

直接调用useNavigation()即可获取共享状态:

<script setup>
import Header from "@/Components/Header.vue";
import Nav from "@/Components/Nav.vue";
import { useNavigation } from "@/Composables/useNavigation";

const { isScroll, isHamburgerClosed, isNavClosed, enterLeaveNav } = useNavigation();
</script>

<template>
    <div>
        <header class="header container">
            <Header />
        </header>
        <div class="container-fluid">
            <div class="row g-0">
                <nav
                    class="p-0 nav"
                    :class="[
                        isScroll ? 'overflowScroll' : 'overflowHidden',
                        isNavClosed ? 'width833' : 'width1633',
                    ]"
                    @mouseenter="enterLeaveNav"
                    @mouseleave="enterLeaveNav"
                >
                    <Nav />
                </nav>
                <main
                    class="ps-5"
                    :class="[
                        isNavClosed
                            ? 'offset-md-1 col-md-10'
                            : 'offset-md-2 col-md-9',
                    ]"
                    style="margin-top: 100px"
                >
                    <slot name="content" />
                </main>
            </div>
        </div>
    </div>
</template>

同样调用useNavigation()获取同一状态:

<script setup>
import { useNavigation } from "@/Composables/useNavigation";

const { isHamburgerClosed, toggleNav } = useNavigation();
</script>

<template>
  <div
    class="hamburgerMenu"
    :class="isHamburgerClosed ? 'hamburgerMenuMarginLeft2' : 'hamburgerMenuMarginLeft80'"
    @click="toggleNav"
  >
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
  </div>
</template>

方案3:子组件emit状态变化给父组件

子组件在汉堡菜单状态改变时,通过emit事件通知父组件更新状态,父组件统一维护状态:

修改Nav.vue

定义emit事件,在状态变化时通知父组件:

<script setup>
import { ref, defineEmits } from 'vue'

const emit = defineEmits(['update:hamburgerState'])
const isHamburgerClosed = ref(true)

const toggleNav = () => {
  isHamburgerClosed.value = !isHamburgerClosed.value
  // 向父组件发送状态更新事件
  emit('update:hamburgerState', isHamburgerClosed.value)
  // 保留原有的菜单切换逻辑
}
</script>

<template>
  <div
    class="hamburgerMenu"
    :class="isHamburgerClosed ? 'hamburgerMenuMarginLeft2' : 'hamburgerMenuMarginLeft80'"
    @click="toggleNav"
  >
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
    <div class="hamburgerPiece"></div>
  </div>
</template>

修改父组件

接收子组件的状态更新,维护isHamburgerClosed的值:

<script setup>
import Header from "@/Components/Header.vue";
import Nav from "@/Components/Nav.vue";
import { ref } from "vue";

const isScroll = ref(false);
const isNavClosed = ref(false);
const isHamburgerClosed = ref(true)

function setIsNavClosed() {
    isNavClosed.value = !isNavClosed.value;
}

function enterLeaveNav() {
    isScroll.value = !isScroll.value;
    if (isHamburgerClosed.value) {
        isNavClosed.value = !isNavClosed.value;
    }
}

// 接收子组件的状态更新
const updateHamburgerState = (newState) => {
  isHamburgerClosed.value = newState
}
</script>

<template>
    <div>
        <header class="header container">
            <Header />
        </header>
        <div class="container-fluid">
            <div class="row g-0">
                <nav
                    class="p-0 nav"
                    :class="[
                        isScroll ? 'overflowScroll' : 'overflowHidden',
                        isNavClosed ? 'width833' : 'width1633',
                    ]"
                    @mouseenter="enterLeaveNav"
                    @mouseleave="enterLeaveNav"
                >
                    <Nav @update:hamburgerState="updateHamburgerState" @open-close-nav="setIsNavClosed" />
                </nav>
                <main
                    class="ps-5"
                    :class="[
                        isNavClosed
                            ? 'offset-md-1 col-md-10'
                            : 'offset-md-2 col-md-9',
                    ]"
                    style="margin-top: 100px"
                >
                    <slot name="content" />
                </main>
            </div>
        </div>
    </div>
</template>

内容的提问来源于stack exchange,提问作者ahmad kharabsheh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:37:36